SvelteKit API Routes — +server.js로 백엔드 API 만들기
SvelteKit에서는 프론트엔드와 백엔드 API를 같은 프로젝트에서 만들 수 있습니다.
개념 정의
API Routes 는 +server.js 파일에서 HTTP 메서드별 핸들러를 export하여 RESTful API 엔드포인트를 만드는 기능입니다. Next.js의 Route Handlers와 동일한 개념입니다.
기본 사용법
// src/routes/api/posts/+server.js
import { json, error } from '@sveltejs/kit';
// GET /api/posts
export async function GET({ url }) {
const page = Number(url.searchParams.get('page') ?? '1');
const limit = Number(url.searchParams.get('limit') ?? '10');
const posts = await db.post.findMany({
skip: (page - 1) * limit,
take: limit,
});
return json(posts);
}
// POST /api/posts
export async function POST({ request }) {
const body = await request.json();
if (!body.title || !body.content) {
error(400, '제목과 내용은 필수입니다');
}
const post = await db.post.create({ data: body });
return json(post, { status: 201 });
}
CRUD API 패턴
// src/routes/api/posts/[id]/+server.js
import { json, error } from '@sveltejs/kit';
// GET /api/posts/:id
export async function GET({ params }) {
const post = await db.post.findUnique({
where: { id: params.id }
});
if (!post) {
error(404, '포스트를 찾을 수 없습니다');
}
return json(post);
}
// PUT /api/posts/:id
export async function PUT({ params, request }) {
const body = await request.json();
const post = await db.post.update({
where: { id: params.id },
data: body,
});
return json(post);
}
// DELETE /api/posts/:id
export async function DELETE({ params }) {
await db.post.delete({ where: { id: params.id } });
return new Response(null, { status: 204 });
}
응답 헤더 설정
export async function GET() {
const data = await fetchData();
return json(data, {
headers: {
'Cache-Control': 'max-age=60',
'X-Custom-Header': 'value',
}
});
}
// 스트리밍 응답
export async function GET() {
const stream = new ReadableStream({
start(controller) {
controller.enqueue('Hello ');
controller.enqueue('World');
controller.close();
}
});
return new Response(stream, {
headers: { 'Content-Type': 'text/plain' }
});
}
인증 미들웨어 패턴
// src/routes/api/posts/+server.js
import { json, error } from '@sveltejs/kit';
export async function POST({ request, locals }) {
// hooks.server.js에서 설정한 인증 정보 확인
if (!locals.user) {
error(401, '인증이 필요합니다');
}
const body = await request.json();
const post = await db.post.create({
data: { ...body, authorId: locals.user.id }
});
return json(post, { status: 201 });
}
Webhook 처리
// src/routes/api/webhook/stripe/+server.js
import { error } from '@sveltejs/kit';
import { STRIPE_WEBHOOK_SECRET } from '$env/static/private';
export async function POST({ request }) {
const body = await request.text();
const signature = request.headers.get('stripe-signature');
try {
const event = stripe.webhooks.constructEvent(
body, signature, STRIPE_WEBHOOK_SECRET
);
switch (event.type) {
case 'payment_intent.succeeded':
await handlePaymentSuccess(event.data.object);
break;
case 'customer.subscription.deleted':
await handleSubscriptionCanceled(event.data.object);
break;
}
return new Response('OK', { status: 200 });
} catch (err) {
error(400, `Webhook Error: ${err.message}`);
}
}
면접 포인트
- "API Routes와 Form Actions의 차이는?": API Routes는 범용 HTTP 엔드포인트로 외부 클라이언트도 사용할 수 있습니다. Form Actions는 SvelteKit 폼에 특화되어 프로그레시브 인핸스먼트, CSRF 보호를 기본 제공합니다.
- "CORS는 어떻게 처리하나요?":
+server.js에서 OPTIONS 핸들러를 추가하고 응답 헤더에Access-Control-Allow-Origin을 설정하거나, hooks에서 일괄 처리할 수 있습니다.
정리
SvelteKit의 API Routes는 풀스택 개발을 가능하게 하는 핵심 기능입니다. 파일 기반으로 API를 구성하니 구조가 직관적이고, SvelteKit의 타입 시스템과 에러 처리를 그대로 활용할 수 있습니다.
댓글 로딩 중...