
Next.js๋ ๋จ์ํ ํ๋ก ํธ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋์ด, ๋ฐฑ์๋ ๋ก์ง์ ์ง์ ํ์ ์ ์๋ Route Handlers (๊ตฌ API Routes) ๊ธฐ๋ฅ์ ์ ๊ณตํจ. app/api ๋๋ ํฐ๋ฆฌ์ route.ts ํ์ผ์ ์์ฑํ๋ ๊ฒ๋ง์ผ๋ก ์๋ฒ๋ฆฌ์ค API ์๋ํฌ์ธํธ๊ฐ ๋ง๋ค์ด์ง.
๋๋ถ์ ๋ฐฑ์๋ ์๋ฒ ์์ด๋ ํ์คํ ๊ฐ๋ฐ์ด ๊ฐ๋ฅํ๋ฉฐ, ํ๋ก ํธ์๋์ ๋ฐฑ์๋๋ฅผ ํ ํ๋ก์ ํธ(Monorepo)์์ ๊ด๋ฆฌํ์ฌ ํ์ ๊ณต์ , ๊ฐ๋ฐ ๋ฐ ๋ฐฐํฌ ํ์ดํ๋ผ์ธ ๋จ์ํ ๋ฑ ๊ฐ๋ ฅํ ์ด์ ์ ์ ๊ณตํจ.
App Router ํ๊ฒฝ์์ API ์๋ํฌ์ธํธ๋ฅผ ์์ฑํ๋ ๊ณต์ ๋ช
์นญ์. (Pages Router์์๋ 'API Routes'๋ก ๋ถ๋ ธ์). app ํด๋ ๋ด ํน์ ๊ฒฝ๋ก์ route.ts ๋๋ route.js ํ์ผ์ ์์น์ํค๋ฉด ๋จ. ํ์ผ ์์์๋ GET, POST, PUT, PATCH, DELETE ๋ฑ HTTP ๋ฉ์๋ ์ด๋ฆ์ผ๋ก ํจ์๋ฅผ exportํ์ฌ ์์ฒญ์ ์ฒ๋ฆฌํจ.
Next.js์ ํต์ฌ ์์น์ผ๋ก, ํ์ผ ์์คํ ๊ตฌ์กฐ๊ฐ URL ์ฃผ์๋ก ์ง๊ฒฐ๋จ.
app/api/users/route.ts โ /api/usersapp/api/users/[id]/route.ts โ /api/users/123, /api/users/abcapp/api/files/[...slug]/route.ts โ /api/files/a/b/cRoute Handler ํจ์๋ ์น ํ์ค API์ธ Request ๊ฐ์ฒด๋ฅผ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ๋ฐ์. ๋ ๋ฒ์งธ ์ธ์๋ก๋ ๋์ ๋ผ์ฐํ
์ ํ๋ผ๋ฏธํฐ(params) ๋ฑ์ ํฌํจํ๋ ๊ฐ์ฒด๋ฅผ ๋ฐ์ ์ ์์.
์๋ต์ ๋ณด๋ผ ๋๋ ์น ํ์ค Response ๊ฐ์ฒด๋, ํธ์ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋ Next.js์ NextResponse ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํจ. NextResponse.json()์ JSON ์๋ต์, NextResponse.redirect()๋ ๋ฆฌ๋ค์ด๋ ์
์ ์ฝ๊ฒ ์ฒ๋ฆฌํ๋๋ก ๋์์ค.
์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ์กฐํ, ์์ฑ, ์์ , ์ญ์ ํ๋ ์ ์ฒด์ ์ธ API ์์
// ํ์ผ ์์น: app/api/users/route.ts
import { NextResponse } from 'next/server';
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ญํ ์ ํ๋ ๋ชจ์ ๋ฐ์ดํฐ
let users = [
{ id: 1, name: 'Kim', email: 'kim@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
];
/**
* GET /api/users
* ๋ชจ๋ ์ฌ์ฉ์ ๋ชฉ๋ก์ ์กฐํํจ.
*/
export async function GET() {
// ์ค์ ์ฑ์์๋ DB์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ๋ก์ง์ด ๋ค์ด๊ฐ
return NextResponse.json({ users });
}
/**
* POST /api/users
* ์๋ก์ด ์ฌ์ฉ์๋ฅผ ์์ฑํจ.
*/
export async function POST(request: Request) {
try {
const { name, email } = await request.json();
// ๊ฐ๋จํ ์ ํจ์ฑ ๊ฒ์ฌ (์ค์ ๋ก๋ Zod, Joi ๋ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ๊ถ์ฅ)
if (!name || !email) {
return NextResponse.json(
{ message: 'Name and email are required' },
{ status: 400 } // Bad Request
);
}
const newUser = { id: users.length + 1, name, email };
users.push(newUser);
return NextResponse.json(
{ message: 'User created successfully', user: newUser },
{ status: 201 } // Created
);
} catch (error) {
return NextResponse.json(
{ message: 'Invalid request body' },
{ status: 400 }
);
}
}
// ํ์ผ ์์น: app/api/users/[id]/route.ts
import { NextResponse } from 'next/server';
// ์ ํ์ผ์ users ๋ฐฐ์ด์ ๊ณต์ ํ๋ค๊ณ ๊ฐ์ ํจ (์ค์ ๋ก๋ DB ์ฌ์ฉ)
let users = [
{ id: 1, name: 'Kim', email: 'kim@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
];
/**
* GET /api/users/[id]
* ํน์ ID์ ์ฌ์ฉ์๋ฅผ ์กฐํํจ.
* @param params - { id: string } ํํ์ ๋์ ์ธ๊ทธ๋จผํธ
*/
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
const userId = parseInt(params.id, 10);
const user = users.find((u) => u.id === userId);
if (!user) {
return NextResponse.json({ message: 'User not found' }, { status: 404 });
}
return NextResponse.json({ user });
}
/**
* PATCH /api/users/[id]
* ํน์ ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ๋ถ๋ถ์ ์ผ๋ก ์์ ํจ.
*/
export async function PATCH(
request: Request,
{ params }: { params: { id: string } }
) {
const userId = parseInt(params.id, 10);
const userIndex = users.findIndex((u) => u.id === userId);
if (userIndex === -1) {
return NextResponse.json({ message: 'User not found' }, { status: 404 });
}
const body = await request.json();
// ๊ธฐ์กด ๋ฐ์ดํฐ์ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๋ฎ์ด์
users[userIndex] = { ...users[userIndex], ...body };
return NextResponse.json({
message: 'User updated',
user: users[userIndex],
});
}
/**
* DELETE /api/users/[id]
* ํน์ ์ฌ์ฉ์๋ฅผ ์ญ์ ํจ.
*/
export async function DELETE(
request: Request,
{ params }: { params: { id: string } }
) {
const userId = parseInt(params.id, 10);
const initialLength = users.length;
users = users.filter((u) => u.id !== userId);
if (users.length === initialLength) {
return NextResponse.json({ message: 'User not found' }, { status: 404 });
}
// ์ฑ๊ณต์ ์ผ๋ก ์ญ์ ๋์์ง๋ง, ๋ฐํํ ์ฝํ
์ธ ๊ฐ ์์
return new NextResponse(null, { status: 204 });
}
route.ts ํ์ผ์์ export const dynamic = 'force-dynamic' ๊ณผ ๊ฐ์ ์ต์
์ ์ค์ ํ์ฌ ์บ์ฑ ๋์์ ์ ์ดํ๊ฑฐ๋, ์ฃ์ง(Edge) ํ๊ฒฝ์์ ํจ์๋ฅผ ์คํํ๋๋ก ์ง์ ํ ์ ์์.middleware.ts ํ์ผ์ ์ฌ์ฉํ์ฌ API ์์ฒญ์ด ํธ๋ค๋ฌ์ ๋๋ฌํ๊ธฐ ์ ์ ์ธ์ฆ(Authentication), ๋ก๊น
, ๋ฆฌ๋ค์ด๋ ํธ ๋ฑ์ ์ค์์์ ์ผ๊ด ์ฒ๋ฆฌํ ์ ์์. API ๋ณด์๊ณผ ๊ด๋ฆฌ์ ํ์์ ์.try-catch ๊ตฌ๋ฌธ์ ์ ๊ทน์ ์ผ๋ก ์ฌ์ฉํ์ฌ ์์์น ๋ชปํ ์ค๋ฅ๋ฅผ ์ก๊ณ , ์ผ๊ด๋ ํ์์ ์๋ฌ ๋ฉ์์ง์ ์ ์ ํ HTTP ์ํ ์ฝ๋๋ฅผ ๋ฐํํ๋ ๊ฒ์ด ์ค์ํจ.https://nextjs-ko.org/docs/app/building-your-application/routing/route-handlers