Next.js Route Handlers

CH.devยท2025๋…„ 7์›” 30์ผ
post-thumbnail

๐Ÿ“„ ์š”์•ฝ

Next.js๋Š” ๋‹จ์ˆœํ•œ ํ”„๋ก ํŠธ์—”๋“œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋„˜์–ด, ๋ฐฑ์—”๋“œ ๋กœ์ง์„ ์ง์ ‘ ํ’ˆ์„ ์ˆ˜ ์žˆ๋Š” Route Handlers (๊ตฌ API Routes) ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•จ. app/api ๋””๋ ‰ํ„ฐ๋ฆฌ์— route.ts ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ์„œ๋ฒ„๋ฆฌ์Šค API ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋งŒ๋“ค์–ด์ง.

๋•๋ถ„์— ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ์—†์ด๋„ ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ๋ฅผ ํ•œ ํ”„๋กœ์ ํŠธ(Monorepo)์—์„œ ๊ด€๋ฆฌํ•˜์—ฌ ํƒ€์ž… ๊ณต์œ , ๊ฐœ๋ฐœ ๋ฐ ๋ฐฐํฌ ํŒŒ์ดํ”„๋ผ์ธ ๋‹จ์ˆœํ™” ๋“ฑ ๊ฐ•๋ ฅํ•œ ์ด์ ์„ ์ œ๊ณตํ•จ.

๐Ÿ’ก ์ฃผ์š” ๊ฐœ๋…

1. Route Handlers

App Router ํ™˜๊ฒฝ์—์„œ API ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ณต์‹ ๋ช…์นญ์ž„. (Pages Router์—์„œ๋Š” 'API Routes'๋กœ ๋ถˆ๋ ธ์Œ). app ํด๋” ๋‚ด ํŠน์ • ๊ฒฝ๋กœ์— route.ts ๋˜๋Š” route.js ํŒŒ์ผ์„ ์œ„์น˜์‹œํ‚ค๋ฉด ๋จ. ํŒŒ์ผ ์•ˆ์—์„œ๋Š” GET, POST, PUT, PATCH, DELETE ๋“ฑ HTTP ๋ฉ”์„œ๋“œ ์ด๋ฆ„์œผ๋กœ ํ•จ์ˆ˜๋ฅผ exportํ•˜์—ฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•จ.

2. ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ… (File-based Routing)

Next.js์˜ ํ•ต์‹ฌ ์›์น™์œผ๋กœ, ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ตฌ์กฐ๊ฐ€ URL ์ฃผ์†Œ๋กœ ์ง๊ฒฐ๋จ.

  • ์ •์  (Static): app/api/users/route.ts โ†’ /api/users
  • ๋™์  (Dynamic): app/api/users/[id]/route.ts โ†’ /api/users/123, /api/users/abc
  • ์ „์ฒด ํฌ๊ด„ (Catch-all): app/api/files/[...slug]/route.ts โ†’ /api/files/a/b/c

3. ์š”์ฒญ(Request)๊ณผ ์‘๋‹ต(Response)

Route Handler ํ•จ์ˆ˜๋Š” ์›น ํ‘œ์ค€ API์ธ Request ๊ฐ์ฒด๋ฅผ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ๋ฐ›์Œ. ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ๋Š” ๋™์  ๋ผ์šฐํŒ…์˜ ํŒŒ๋ผ๋ฏธํ„ฐ(params) ๋“ฑ์„ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ.

์‘๋‹ต์„ ๋ณด๋‚ผ ๋•Œ๋Š” ์›น ํ‘œ์ค€ Response ๊ฐ์ฒด๋‚˜, ํŽธ์˜ ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋œ Next.js์˜ NextResponse ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•จ. NextResponse.json()์€ JSON ์‘๋‹ต์„, NextResponse.redirect()๋Š” ๋ฆฌ๋‹ค์ด๋ ‰์…˜์„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋„์™€์คŒ.

๐Ÿง  ์ฝ”๋“œ ์˜ˆ์‹œ: ์‚ฌ์šฉ์ž(Users) API

์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒ, ์ƒ์„ฑ, ์ˆ˜์ •, ์‚ญ์ œํ•˜๋Š” ์ „์ฒด์ ์ธ API ์˜ˆ์‹œ

1. ์‚ฌ์šฉ์ž ๋ชฉ๋ก ์กฐํšŒ ๋ฐ ์ƒ์„ฑ

// ํŒŒ์ผ ์œ„์น˜: 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 }
    );
  }
}

2. ํŠน์ • ์‚ฌ์šฉ์ž ์กฐํšŒ, ์ˆ˜์ •, ์‚ญ์ œ (๋™์  ๋ผ์šฐํŠธ)

// ํŒŒ์ผ ์œ„์น˜: 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 });
}

๐Ÿ” ๋” ๊นŠ์ด ์•Œ์•„๋ณด๊ธฐ

  1. Route Segment Config: route.ts ํŒŒ์ผ์—์„œ export const dynamic = 'force-dynamic' ๊ณผ ๊ฐ™์€ ์˜ต์…˜์„ ์„ค์ •ํ•˜์—ฌ ์บ์‹ฑ ๋™์ž‘์„ ์ œ์–ดํ•˜๊ฑฐ๋‚˜, ์—ฃ์ง€(Edge) ํ™˜๊ฒฝ์—์„œ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Œ.
  2. ๋ฏธ๋“ค์›จ์–ด (Middleware): middleware.ts ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์—ฌ API ์š”์ฒญ์ด ํ•ธ๋“ค๋Ÿฌ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ์ธ์ฆ(Authentication), ๋กœ๊น…, ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋“ฑ์„ ์ค‘์•™์—์„œ ์ผ๊ด„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ. API ๋ณด์•ˆ๊ณผ ๊ด€๋ฆฌ์— ํ•„์ˆ˜์ ์ž„.
  3. ์—๋Ÿฌ ํ•ธ๋“ค๋ง (Error Handling): try-catch ๊ตฌ๋ฌธ์„ ์ ๊ทน์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜๋ฅผ ์žก๊ณ , ์ผ๊ด€๋œ ํ˜•์‹์˜ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€์™€ ์ ์ ˆํ•œ HTTP ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•จ.

https://nextjs-ko.org/docs/app/building-your-application/routing/route-handlers

profile
๋” ์ด์ƒ ๋ฏธ๋ฃฐ ์ˆ˜ ์—†๋‹ค ๋‚˜์˜ ๊ณต๋ถ€ ๋‚˜์˜ ์„ฑ์žฅ

0๊ฐœ์˜ ๋Œ“๊ธ€