[ Routing ] Route Handlers

차차·2023년 5월 17일
0

Next Docs

목록 보기
12/34
post-thumbnail

Route Hadnlers

Route Handlers를 사용하면 Web 요청 및 응답 API를 사용하여 특정 경로에 대한 사용자 정의 요청 핸들러를 만들 수 있다.

Route Handlers는 app 디렉토리 내에서만 사용할 수 있다. 이는 pages 디렉토리 내의 API Routes와 동등한 기능을 제공하므로 API Routes와 Route Handlers를 함께 사용할 필요가 없다.


규칙

Route Handlersapp 디렉토리 내에 route.js 파일로 정의된다.

// app/api/route.ts

export async function GET(request: Request) {}

Route Handlers는 page.jslayout.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는 NextRequestNextResponse를 확장하여 고급 사용 사례에 유용한 도우미를 제공한다.


동작 방식

정적 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 객체를 사용할 때.
  • 다른 모든 HTTP 메서드를 사용할 때.
  • 쿠키헤더와 같은 동적 함수를 사용할 때.
  • 세그먼트 구성 옵션에서 동적 모드를 수동으로 지정하는 경우.
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 파일이 존재할 수 없습니다.
PageRouteResult
app/page.jsapp/route.jsConflict
app/page.jsapp/api/route.jsValid
app/[user]/page.jsapp/api/route.jsValid

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의 cookiesheaders와 같은 동적 함수와 함께 사용할 수 있다.


💡  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'
}
RouteExample URLparams
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 메서드를 사용하여 responseCORS 헤더를 설정할 수 있다.

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

profile
나는야 프린이

0개의 댓글