본문 바로가기

개발 공부/React

Next.js API Route

App Router를 쓰면, 프론트 페이지(page.tsx)뿐 아니라 서버에서 실행되는 API 엔드포인트도 app 폴더 아래에서 함께 관리할 수 있습니다.

왜 app/api/.../route.ts로 API를 만들까?

App Router의 핵심은 “라우트는 폴더 구조로 결정된다” 입니다.

  • app/(something)/page.tsx → 페이지 라우트
  • app/api/(something)/route.ts → API 라우트

즉, route.ts는 “이 폴더 경로에 해당하는 요청을 처리하는 서버 핸들러”라는 의미입니다.

이렇게 쓰는 이유

  1. 프론트 + API를 한 프로젝트에서 통합 관리
    • 별도의 Express/Nest 서버 없이도 가벼운 백엔드 역할을 수행
  2. 서버 코드가 자동으로 서버에서만 실행
    • 이메일 발송 같은 민감한 로직(비밀키 사용, SMTP/API 호출 등)을 브라우저에 노출하지 않음
  3. 서버 컴포넌트/액션과 자연스럽게 연결
    • 폼 제출, 웹훅, 백오피스 작업 등 “서버에서 해야 하는 일”을 라우트로 분리

 


폴더 구조가 URL이 되는 규칙

예를 들어 이런 구조

app/
  api/
    send-appointment-email/
      route.ts
  • 이 파일은 URL로는 이렇게 매핑됩니다
    • /api/send-appointment-email

즉, 폴더 이름(send-appointment-email)이 곧 API 경로가 되는 셈이에요.

 


route.ts에는 뭘 써야 하나요?

route.ts에서는 HTTP 메서드 별로 함수 export를 합니다.

  • export async function GET(req: Request) { ... }
  • export async function POST(req: Request) { ... }
  • export async function PUT(req: Request) { ... }
  • export async function DELETE(req: Request) { ... }

그리고 응답은 보통 NextResponse.json(...)로 반환합니다.


예시: 예약 이메일 발송 API (POST)

// app/api/send-appointment-email/route.ts
import { NextResponse } from "next/server";

type Body = {
  to: string;
  customerName: string;
  appointmentAt: string; // ISO string 추천
};

export async function POST(req: Request) {
  try {
    const body = (await req.json()) as Body;

    // 1) 기본 검증
    if (!body.to || !body.customerName || !body.appointmentAt) {
      return NextResponse.json(
        { ok: false, message: "필수 값이 누락되었습니다." },
        { status: 400 }
      );
    }

    // 2) 이메일 발송 로직 (예: Resend, SendGrid, Nodemailer 등)
    // await sendEmail({ to: body.to, ... });

    return NextResponse.json({ ok: true });
  } catch (err) {
    return NextResponse.json(
      { ok: false, message: "서버 에러가 발생했습니다." },
      { status: 500 }
    );
  }
}
  • route.ts는 브라우저가 아니라 서버에서 실행되기 때문에, 이메일 API 키 같은 값을 환경변수로 안전하게 쓸 수 있어요.

 


 

프론트에서 이 API를 어떻게 호출하나요?

(1) Client Component에서 fetch로 호출

async function sendAppointmentEmail() {
  const res = await fetch("/api/send-appointment-email", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      to: "test@example.com",
      customerName: "홍길동",
      appointmentAt: new Date().toISOString(),
    }),
  });

  const data = await res.json();
  if (!res.ok) throw new Error(data.message ?? "요청 실패");
}

(2) Server Action/서버 컴포넌트에서 호출

서버 쪽에서 이미 작업한다면, 굳이 API를 한 번 더 거치지 않고 직접 이메일 발송 함수를 호출하는 패턴도 많습니다.

  • 사용자 입력(브라우저) → 서버로 보내야 하는 경우: API Route가 편함
  • 이미 서버 내부 흐름(크론, 웹훅, 서버 컴포넌트)이라면: 함수 호출이 더 간단

 

'개발 공부 > React' 카테고리의 다른 글

React useMutation + invalidateQueries  (0) 2026.01.13
Clerk PricingTable  (0) 2025.12.25
탭 간 상태 동기화 - React  (0) 2025.12.21
Clerk 로그인/회원가입  (0) 2025.11.29
UploadThing을 통한 이미지 업로드 구현하기  (0) 2025.11.27