Route Handlers를 사용하면 Web 요청 및 응답 API를 사용하여 특정 경로에 대한 사용자 정의 요청 핸들러를 만들 수 있다.
Route Handlers는 app
디렉토리 내에서만 사용할 수 있다. 이는 pages
디렉토리 내의 API Routes와 동등한 기능을 제공하므로 API Routes와 Route Handlers를 함께 사용할 필요가 없다.
Route Handlers는 app
디렉토리 내에 route.js
파일로 정의된다.
// app/api/route.ts
export async function GET(request: Request) {}
Route Handlers는 page.js
및 layout.js
와 유사하게 app
디렉토리 내에서 중첩될 수 있다. 그러나 route.js
파일은 page.js
와 동일한 경로 세그먼트 수준에 존재할 수 없다.
지원되는 HTTP 메소드
지원되는 HTTP 메소드는 아래와 같다.
GET
POST
PUT
PATCH
DELETE
HEAD
OPTIONS
지원되지 않는 메서드를 호출하면 Next.js가 405 Method Not Allowed
응답을 반환한다.
확장된 NextRequest 및 NextResponse API
네이티브 Request 및 Response를 지원하는 것 외에도 Next.js는 NextRequest
및 NextResponse
를 확장하여 고급 사용 사례에 유용한 도우미를 제공한다.
정적 Route Handlers
GET
메서드와 Response
객체를 사용할 때, 기본적으로 Route Handlers는 정적으로 평가된다.
import { NextResponse } from 'next/server';
export async function GET() {
const res = await fetch('https://data.mongodb-api.com/...', {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
});
const data = await res.json();
return NextResponse.json({ data });
}
TypeScript 경고: Response.json()
은 유효하지만, 현재 네이티브 TypeScript 유형에서 오류가 표시된다. 대신 타입이 지정된 응답을 위해 NextResponse.json()
을 사용할 수 있다.
동적 Route Hadlers
Route Handlers는 다음 경우 동적으로 평가된다.
GET
메서드와 Request
객체를 사용할 때.쿠키
와 헤더
와 같은 동적 함수를 사용할 때.import { NextResponse } from 'next/server';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
const res = await fetch(`https://data.mongodb-api.com/product/${id}`, {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
});
const product = await res.json();
return NextResponse.json({ product });
}
마찬가지로, POST
메서드는 Route Handler가 동적으로 평가되도록 한다.
import { NextResponse } from 'next/server';
export async function POST() {
const res = await fetch('https://data.mongodb-api.com/...', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
body: JSON.stringify({ time: new Date().toISOString() }),
});
const data = await res.json();
return NextResponse.json(data);
}
이전에는 API Routes를 사용하여 폼 제출과 같은 사용 사례를 처리할 수 있었다. Route Handlers는 이러한 사용 사례에는 적합하지 않을 수 있다. 준비되면 이를 위해 변이(mutations)의 사용을 권장하고 있다.
Route Resolution
경로를 가장 기본적인 라우팅 프리미티브로 간주할 수 있다.
page.js
와 같은 경로에 route.js
파일이 존재할 수 없습니다.Page | Route | Result |
---|---|---|
app/page.js | app/route.js | Conflict |
app/page.js | app/api/route.js | Valid |
app/[user]/page.js | app/api/route.js | Valid |
각 route.js
또는 page.js
파일은 해당 경로에 대한 모든 HTTP 동사(verbs)를 담당한다.
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
// ❌ Conflict
// `app/route.js`
export async function POST(request) {}
다음 예시들은 Route Handlers를 다른 Next.js API 및 기능과 함께 사용하는 방법을 보여준다.
정적 데이터 유효성 재검사
정적 데이터를 다시 유효성 검사할 때는 next.revalidate
옵션을 사용할 수 있다.
import { NextResponse } from 'next/server';
export async function GET() {
const res = await fetch('https://data.mongodb-api.com/...', {
next: { revalidate: 60 }, // Revalidate every 60 seconds
});
const data = await res.json();
return NextResponse.json(data);
}
또는 revalidate
세그먼트 구성 옵션을 사용할 수도 있다.
export const revalidate = 60;
동적 함수
Route Handlers는 Next.js의 cookies
와 headers
와 같은 동적 함수와 함께 사용할 수 있다.
💡 Cookies
cookies from next/headers
를 사용하여 쿠키를 읽을 수 있다. 이 서버 함수는 Route Handler 내에서 직접 호출하거나 다른 함수 내에 중첩하여 사용할 수 있다.
이 cookies
인스턴스는 읽기 전용이다. 쿠키를 설정하려면 Set-Cookie
헤더를 사용하여 새로운 Response를 반환해야 한다.
import { cookies } from 'next/headers';
export async function GET(request: Request) {
const cookieStore = cookies();
const token = cookieStore.get('token');
return new Response('Hello, Next.js!', {
status: 200,
headers: { 'Set-Cookie': `token=${token}` },
});
}
또한 웹 API 기반의 추상화를 사용하여 쿠키를 읽을 수도 있다. (NextRequest
)
import { type NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
const token = request.cookies.get('token');
}
💡 headers
headers
from next/headers
를 사용하여 헤더를 읽을 수 있다. 이 서버 함수는 Route Handler 내에서 직접 호출하거나 다른 함수 내에 중첩하여 사용할 수 있다.
이 headers
인스턴스는 읽기 전용이다. 헤더를 설정하려면 새로운 헤더를 가진 새로운 Response를 반환해야 한다.
import { headers } from 'next/headers';
export async function GET(request: Request) {
const headersList = headers();
const referer = headersList.get('referer');
return new Response('Hello, Next.js!', {
status: 200,
headers: { referer: referer },
});
}
또한 웹 API 기반의 추상화를 사용하여 헤더를 읽을 수도 있다. (NextRequest
)
import { type NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
const requestHeaders = new Headers(request.headers);
}
Redirects
import { redirect } from 'next/navigation';
export async function GET(request: Request) {
redirect('https://nextjs.org/');
}
Dynamic Route Segments
Route Handlers는 동적 데이터로부터 요청 핸들러를 생성하기 위해 동적 세그먼트를 사용할 수 있다.
export async function GET(
request: Request,
{
params,
}: {
params: { slug: string };
},
) {
const slug = params.slug; // 'a', 'b', or 'c'
}
Route | Example URL | params |
---|---|---|
app/items/[slug]/route.js | /items/a | { slug: 'a' } |
app/items/[slug]/route.js | /items/b | { slug: 'b' } |
app/items/[slug]/route.js | /items/c | { slug: 'c' } |
Streaming
// https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream#convert_async_iterator_to_stream
function iteratorToStream(iterator: any) {
return new ReadableStream({
async pull(controller) {
const { value, done } = await iterator.next();
if (done) {
controller.close();
} else {
controller.enqueue(value);
}
},
});
}
function sleep(time: number) {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
}
const encoder = new TextEncoder();
async function* makeIterator() {
yield encoder.encode('<p>One</p>');
await sleep(200);
yield encoder.encode('<p>Two</p>');
await sleep(200);
yield encoder.encode('<p>Three</p>');
}
export async function GET() {
const iterator = makeIterator();
const stream = iteratorToStream(iterator);
return new Response(stream);
}
Request Body
표준 웹 API 메서드를 사용하여 request
본문을 읽을 수 있다.
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
const res = await request.json();
return NextResponse.json({ res });
}
CORS
표준 웹 API 메서드를 사용하여 response
에 CORS 헤더를 설정할 수 있다.
export async function GET(request: Request) {
return new Response('Hello, Next.js!', {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
});
}
Edge와 Node.js 런타임
Route Handlers는 Edge와 Node.js 런타임을 완벽하게 지원하기 위해 동일한 웹 API를 가지고 있으며, 스트리밍을 포함한 기능을 제공한다. Route Handlers는 페이지와 레이아웃과 동일한 경로 세그먼트 구성을 사용하므로 일반적인 정적으로 재생성된 Route Handlers와 같은 오랫동안 기다려온 기능을 지원한다..
runtime
세그먼트 구성 옵션을 사용하여 런타임을 지정할 수 있다.
export const runtime = 'edge'; // 'nodejs' is the default
Non-UI Responses
Route Handlers를 사용하여 UI가 아닌 내용을 반환할 수 있다. sitemap.xml
, robots.txt
, favicon.ico
및 오픈 그래프 이미지는 모두 내장된 SEO 지원을 갖고 있음에 유의해야한다.
export async function GET() {
return new Response(`<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Next.js Documentation</title>
<link>https://nextjs.org/docs</link>
<description>The React Framework for the Web</description>
</channel>
</rss>`);
}
세그먼트 설정 옵션
Route Handlers는 페이지와 레이아웃과 동일한 라우트 세그먼트 구성을 사용한다.
export const dynamic = 'auto';
export const dynamicParams = true;
export const revalidate = false;
export const fetchCache = 'auto';
export const runtime = 'nodejs';
export const preferredRegion = 'auto';
[ 출처 ]
https://nextjs.org/docs/app/building-your-application/routing/router-handlers