Next.js API Routes를 탐색하고 React 애플리케이션 내에서 풀스택 개발 역량을 발휘하세요. 패턴, 모범 사례, 배포 전략을 알아보세요.
Next.js API Routes: 풀스택 개발 패턴
Next.js는 성능이 뛰어나고 확장 가능한 웹 애플리케이션을 구축하기 위한 강력한 프레임워크를 제공함으로써 React 개발에 혁명을 일으켰습니다. 핵심 기능 중 하나는 개발자가 Next.js 프로젝트 내에서 직접 백엔드 기능을 생성할 수 있게 해주는 API Routes입니다. 이 접근 방식은 개발을 간소화하고 배포를 단순화하며 강력한 풀스택 기능을 제공합니다.
Next.js API Routes란 무엇인가?
Next.js API Routes는 /pages/api
디렉토리 내에 직접 작성된 서버리스 함수입니다. 이 디렉토리의 각 파일은 API 엔드포인트가 되어 HTTP 요청을 해당 함수로 자동 라우팅합니다. 이로 인해 별도의 백엔드 서버가 필요 없어져 애플리케이션 아키텍처가 단순화되고 운영 오버헤드가 줄어듭니다.
Next.js 앱 내부에 존재하는 작은 서버리스 함수라고 생각하면 됩니다. GET, POST, PUT, DELETE와 같은 HTTP 요청에 응답하며 데이터베이스, 외부 API 및 기타 서버사이드 리소스와 상호 작용할 수 있습니다. 결정적으로, 이 함수들은 사용자 브라우저가 아닌 서버에서만 실행되므로 API 키와 같은 민감한 데이터의 보안을 보장합니다.
API Routes의 주요 이점
- 간소화된 개발: 프론트엔드와 백엔드 코드를 동일한 프로젝트 내에서 작성합니다.
- 서버리스 아키텍처: 서버리스 함수를 활용하여 확장성과 비용 효율성을 높입니다.
- 쉬운 배포: 단일 명령어로 프론트엔드와 백엔드를 함께 배포합니다.
- 향상된 성능: 서버사이드 렌더링 및 데이터 페칭 기능이 애플리케이션 속도를 향상시킵니다.
- 강화된 보안: 민감한 데이터는 서버에 남아 클라이언트 측 노출로부터 보호됩니다.
API Routes 시작하기
Next.js에서 API 라우트를 만드는 것은 간단합니다. /pages/api
디렉토리 내에 새 파일을 생성하기만 하면 됩니다. 파일명은 라우트의 경로를 결정합니다. 예를 들어, /pages/api/hello.js
라는 파일을 만들면 /api/hello
에서 접근할 수 있는 API 엔드포인트가 생성됩니다.
예제: 간단한 인사 API
다음은 JSON 응답을 반환하는 API 라우트의 기본 예제입니다:
// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ message: 'Hello from Next.js API Route!' });
}
이 코드는 두 개의 인수를 받는 비동기 함수 handler
를 정의합니다:
req
:http.IncomingMessage
의 인스턴스이며, 일부 사전 빌드된 미들웨어가 추가됩니다.res
:http.ServerResponse
의 인스턴스이며, 일부 헬퍼 함수가 추가됩니다.
이 함수는 HTTP 상태 코드를 200 (OK)으로 설정하고 메시지와 함께 JSON 응답을 반환합니다.
다양한 HTTP 메서드 처리하기
req.method
속성을 확인하여 API 라우트 내에서 다양한 HTTP 메서드(GET, POST, PUT, DELETE 등)를 처리할 수 있습니다. 이를 통해 RESTful API를 쉽게 만들 수 있습니다.
// pages/api/todos.js
export default async function handler(req, res) {
if (req.method === 'GET') {
// 데이터베이스에서 모든 할 일(todos) 가져오기
const todos = await fetchTodos();
res.status(200).json(todos);
} else if (req.method === 'POST') {
// 새로운 할 일(todo) 생성하기
const newTodo = await createTodo(req.body);
res.status(201).json(newTodo);
} else {
// 지원되지 않는 메서드 처리하기
res.status(405).json({ message: 'Method Not Allowed' });
}
}
이 예제는 가상의 /api/todos
엔드포인트에 대한 GET 및 POST 요청을 처리하는 방법을 보여줍니다. 또한 지원되지 않는 메서드에 대한 오류 처리도 포함합니다.
API Routes를 활용한 풀스택 개발 패턴
Next.js API Routes는 다양한 풀스택 개발 패턴을 가능하게 합니다. 다음은 몇 가지 일반적인 사용 사례입니다:
1. 데이터 페칭 및 조작
API Routes는 데이터베이스, 외부 API 또는 기타 데이터 소스에서 데이터를 가져오는 데 사용될 수 있습니다. 또한 레코드 생성, 업데이트 또는 삭제와 같은 데이터 조작에도 사용될 수 있습니다.
예제: 데이터베이스에서 사용자 데이터 가져오기
// pages/api/users/[id].js
import { query } from '../../../lib/db';
export default async function handler(req, res) {
const { id } = req.query;
try {
const results = await query(
'SELECT * FROM users WHERE id = ?',
[id]
);
if (results.length === 0) {
return res.status(404).json({ message: 'User not found' });
}
res.status(200).json(results[0]);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal Server Error' });
}
}
이 예제는 URL에 제공된 사용자 ID를 기반으로 데이터베이스에서 사용자 데이터를 가져옵니다. 데이터베이스와 상호 작용하기 위해 데이터베이스 쿼리 라이브러리(lib/db
에 있다고 가정)를 사용합니다. SQL 인젝션 취약점을 방지하기 위해 매개변수화된 쿼리를 사용하는 점에 유의하세요.
2. 인증 및 인가
API Routes는 인증 및 인가 로직을 구현하는 데 사용될 수 있습니다. 이를 사용하여 사용자 자격 증명을 확인하고, JWT 토큰을 생성하며, 민감한 리소스를 보호할 수 있습니다.
예제: 사용자 인증
// pages/api/login.js
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { query } from '../../lib/db';
export default async function handler(req, res) {
if (req.method === 'POST') {
const { email, password } = req.body;
try {
const results = await query(
'SELECT * FROM users WHERE email = ?',
[email]
);
if (results.length === 0) {
return res.status(401).json({ message: 'Invalid credentials' });
}
const user = results[0];
const passwordMatch = await bcrypt.compare(password, user.password);
if (!passwordMatch) {
return res.status(401).json({ message: 'Invalid credentials' });
}
const token = jwt.sign(
{ userId: user.id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
);
res.status(200).json({ token });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal Server Error' });
}
} else {
res.status(405).json({ message: 'Method Not Allowed' });
}
}
이 예제는 제공된 비밀번호를 데이터베이스에 저장된 해시된 비밀번호와 비교하여 사용자를 인증합니다. 자격 증명이 유효하면 JWT 토큰을 생성하여 클라이언트에 반환합니다. 클라이언트는 이 토큰을 사용하여 후속 요청을 인증할 수 있습니다.
3. 폼 처리 및 데이터 제출
API Routes는 폼 제출을 처리하고 클라이언트에서 보낸 데이터를 처리하는 데 사용될 수 있습니다. 이는 문의 양식, 등록 양식 및 기타 대화형 요소를 만드는 데 유용합니다.
예제: 문의 양식 제출
// pages/api/contact.js
import { sendEmail } from '../../lib/email';
export default async function handler(req, res) {
if (req.method === 'POST') {
const { name, email, message } = req.body;
try {
await sendEmail({
to: 'admin@example.com',
subject: 'New Contact Form Submission',
text: `Name: ${name}\nEmail: ${email}\nMessage: ${message}`,
});
res.status(200).json({ message: 'Email sent successfully' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Failed to send email' });
}
} else {
res.status(405).json({ message: 'Method Not Allowed' });
}
}
이 예제는 관리자에게 이메일을 보내 문의 양식 제출을 처리합니다. 이메일을 보내기 위해 이메일 전송 라이브러리(lib/email
에 있다고 가정)를 사용합니다. admin@example.com
은 실제 수신자 이메일 주소로 교체해야 합니다.
4. 웹훅 및 이벤트 처리
API Routes는 웹훅을 처리하고 외부 서비스의 이벤트에 응답하는 데 사용될 수 있습니다. 이를 통해 Next.js 애플리케이션을 다른 플랫폼과 통합하고 작업을 자동화할 수 있습니다.
예제: Stripe 웹훅 처리하기
// pages/api/stripe-webhook.js
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
export const config = {
api: {
bodyParser: false, // 기본 body 파싱 비활성화
},
};
async function buffer(req) {
const chunks = [];
for await (const chunk of req) {
chunks.push(chunk);
}
return Buffer.concat(chunks).toString();
}
export default async function handler(req, res) {
if (req.method === 'POST') {
const sig = req.headers['stripe-signature'];
let event;
try {
const buf = await buffer(req);
event = stripe.webhooks.constructEvent(buf, sig, process.env.STRIPE_WEBHOOK_SECRET);
} catch (err) {
console.log(`Webhook Error: ${err.message}`);
res.status(400).send(`Webhook Error: ${err.message}`);
return;
}
// 이벤트 처리
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`);
// 성공적인 payment intent를 처리할 메서드를 정의하고 호출합니다.
// handlePaymentIntentSucceeded(paymentIntent);
break;
case 'payment_method.attached':
const paymentMethod = event.data.object;
// PaymentMethod의 성공적인 첨부를 처리할 메서드를 정의하고 호출합니다.
// handlePaymentMethodAttached(paymentMethod);
break;
default:
// 예기치 않은 이벤트 유형
console.log(`Unhandled event type ${event.type}.`);
}
// 이벤트 수신을 확인하는 200 응답 반환
res.status(200).json({ received: true });
} else {
res.setHeader('Allow', 'POST');
res.status(405).end('Method Not Allowed');
}
}
이 예제는 서명을 확인하고 이벤트 데이터를 처리하여 Stripe 웹훅을 처리합니다. 기본 본문 파서를 비활성화하고 사용자 지정 버퍼 함수를 사용하여 원시 요청 본문을 읽습니다. Stripe는 서명 확인을 위해 원시 본문이 필요하므로 기본 본문 파서를 비활성화하는 것이 중요합니다. Stripe 대시보드에서 Stripe 웹훅 엔드포인트를 구성하고 STRIPE_WEBHOOK_SECRET
환경 변수를 설정해야 합니다.
API Routes 모범 사례
API Routes의 품질과 유지보수성을 보장하려면 다음 모범 사례를 따르십시오:
1. 코드 모듈화
크고 단일화된 API 라우트를 작성하는 것을 피하십시오. 대신 코드를 더 작고 재사용 가능한 모듈로 나누십시오. 이렇게 하면 코드를 더 쉽게 이해하고, 테스트하고, 유지보수할 수 있습니다.
2. 오류 처리 구현
API 라우트에서 오류를 적절하게 처리하십시오. try...catch
블록을 사용하여 예외를 포착하고 클라이언트에 적절한 오류 응답을 반환하십시오. 디버깅 및 모니터링에 도움이 되도록 오류를 기록하십시오.
3. 입력 데이터 유효성 검사
보안 취약점을 방지하고 데이터 무결성을 보장하기 위해 항상 클라이언트의 입력 데이터를 유효성 검사하십시오. Joi 또는 Yup과 같은 유효성 검사 라이브러리를 사용하여 유효성 검사 스키마를 정의하고 데이터 제약 조건을 강제하십시오.
4. 민감한 데이터 보호
API 키 및 데이터베이스 자격 증명과 같은 민감한 데이터는 환경 변수에 저장하십시오. 민감한 데이터를 코드 리포지토리에 커밋하지 마십시오.
5. 요청 속도 제한(Rate Limiting) 구현
요청 속도 제한을 구현하여 API 라우트를 남용으로부터 보호하십시오. 이는 클라이언트가 주어진 시간 내에 할 수 있는 요청 수를 제한합니다. express-rate-limit
또는 limiter
와 같은 요청 속도 제한 라이브러리를 사용하십시오.
6. API 키 보안
클라이언트 측 코드에 API 키를 직접 노출하지 마십시오. 항상 API 라우트를 통해 요청을 프록시하여 무단 액세스로부터 API 키를 보호하십시오. 서버의 환경 변수에 API 키를 안전하게 저장하십시오.
7. 환경 변수 사용
코드에 구성 값을 하드코딩하지 마십시오. 대신 환경 변수를 사용하여 구성 설정을 저장하십시오. 이렇게 하면 다른 환경(개발, 스테이징, 프로덕션)에서 애플리케이션을 더 쉽게 관리할 수 있습니다.
8. 로깅 및 모니터링
API 라우트의 성능을 추적하기 위해 로깅 및 모니터링을 구현하십시오. 오류, 경고 및 성공적인 요청과 같은 중요한 이벤트를 기록하십시오. 모니터링 도구를 사용하여 요청 지연 시간, 오류율 및 리소스 사용량과 같은 메트릭을 추적하십시오. Sentry, Datadog 또는 New Relic과 같은 서비스가 도움이 될 수 있습니다.
배포 고려 사항
Next.js API Routes는 서버리스 플랫폼에 배포되도록 설계되었습니다. 인기 있는 배포 옵션은 다음과 같습니다:
- Vercel: Vercel은 Next.js 애플리케이션 배포에 권장되는 플랫폼입니다. Next.js와의 원활한 통합을 제공하고 성능을 위해 애플리케이션을 자동으로 최적화합니다.
- Netlify: Netlify는 Next.js 배포를 지원하는 또 다른 인기 있는 서버리스 플랫폼입니다. 자동 배포 및 CDN 통합과 같은 Vercel과 유사한 기능을 제공합니다.
- AWS Lambda: AWS Lambda는 서버를 프로비저닝하거나 관리하지 않고도 코드를 실행할 수 있는 서버리스 컴퓨팅 서비스입니다. Serverless Framework 또는 AWS SAM과 같은 도구를 사용하여 Next.js API Routes를 Lambda 함수로 배포할 수 있습니다.
- Google Cloud Functions: Google Cloud Functions는 클라우드 서비스를 생성하고 연결할 수 있는 서버리스 실행 환경입니다. Firebase CLI 또는 Google Cloud SDK와 같은 도구를 사용하여 Next.js API Routes를 Cloud Functions로 배포할 수 있습니다.
- Azure Functions: Azure Functions는 인프라를 관리하지 않고도 주문형 코드를 실행할 수 있는 서버리스 컴퓨팅 서비스입니다. Azure Functions Core Tools 또는 Azure CLI와 같은 도구를 사용하여 Next.js API Routes를 Azure Functions로 배포할 수 있습니다.
API Routes와 함께 Next.js 애플리케이션을 배포할 때 배포 플랫폼에서 환경 변수가 올바르게 구성되었는지 확인하십시오. 또한 서버리스 함수의 콜드 스타트 시간도 고려해야 하며, 이는 API 라우트의 초기 응답 시간에 영향을 줄 수 있습니다. 코드를 최적화하고 프로비저닝된 동시성과 같은 기술을 사용하면 콜드 스타트 문제를 완화하는 데 도움이 될 수 있습니다.
결론
Next.js API Routes는 React로 풀스택 애플리케이션을 구축하는 강력하고 편리한 방법을 제공합니다. 서버리스 함수를 활용하여 개발을 단순화하고, 운영 오버헤드를 줄이며, 애플리케이션 성능을 향상시킬 수 있습니다. 이 글에서 설명한 모범 사례를 따르면 Next.js 애플리케이션을 구동하는 견고하고 유지보수 가능한 API Routes를 만들 수 있습니다.
간단한 문의 양식을 구축하든 복잡한 전자 상거래 플랫폼을 구축하든, Next.js API Routes는 개발 프로세스를 간소화하고 뛰어난 사용자 경험을 제공하는 데 도움이 될 수 있습니다.