예시:
API 라우트는 Next.js로 API를 구축할 수 있는 솔루션을 제공합니다.
폴더 pages/api
내에 있는 모든 파일은 /api/*로 매핑되어 페이지 대신 API 엔드포인트로 처리됩니다. 이것들은 서버 사이드에서만 번들링되어 클라이언트 사이드 번들 크기를 증가시키지 않습니다.
예를 들어, 다음 API 라우트 pages/api/user.js
는 상태 코드가 200
인 JSON
응답을 반환합니다:
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' });
}
참고: API 라우트는 next.config.js의 pageExtensions 구성에 영향을 받을 수 있습니다.
API 라우트가 작동하려면 기본(default)으로 함수를 내보내야 합니다. 이 함수는 다음 매개변수를 받습니다.
req
: http.IncomingMessage
의 인스턴스와 몇 가지 미들웨어들res
: http.ServerResponse
의 인스턴스와 몇 가지 헬퍼 함수들API 라우트에서 다른 HTTP 메소드를 처리하려면, 다음과 같이 요청 핸들러 내에서 req.method를 사용할 수 있습니다:
export default function handler(req, res) {
if (req.method === 'POST') {
// POST 요청 처리
} else {
// 다른 모든 HTTP 메소드 처리
}
}
API 엔드포인트를 가져오려면, 이 섹션 시작 부분의 어떤 예시를 살펴보세요.
새 프로젝트의 경우, API 라우트를 사용하여 전체 API를 구축할 수 있습니다. 기존의 API가 있는 경우, 호출을 API 라우트를 통해 전달할 필요가 없습니다. API 라우트의 일부 다른 사용 사례는 다음과 같습니다.
API Routes
는 기본적으로 same-origin
만 허용하는 CORS
헤더를 지정하지 않습니다. CORS
동작을 사용자 정의하려면 요청 핸들러를 CORS
요청 헬퍼로 래핑해야 합니다.API Routes
는 next export
와 함께 사용할 수 없습니다.예시: Basic API Routes(https://github.com/vercel/next.js/tree/canary/examples/api-routes)
API 라우트는 동적 라우트를 지원하며 페이지에서 사용하는 파일 네이밍 규칙과 동일합니다.
예를 들어, 다음과 같은 코드를 가진 API 라우트 pages/api/post/[pid].js
가 있습니다.
export default function handler(req, res) {
const { pid } = req.query;
res.end(`Post: ${pid}`);
}
이제 /api/post/abc
에 대한 요청은 Post: abc
텍스트로 응답합니다.
RESTful
패턴에서 아래와 같은 라우트를 설정하는 것이 매우 일반적입니다.
GET api/posts
- 페이지 목록을 가져옵니다. 아마도 페이지 별로 나뉘어 있습니다.
GET api/posts/12345
- id가 12345인 페이지를 가져옵니다.
이를 다음과 같이 모델링할 수 있습니다.
/api/posts.js
/api/posts/[postId].js
/api/posts/index.js
/api/posts/[postId].js
두 가지 모두 동일합니다. 동적 라우트(캐치 올 라우트를 포함)에는 정의되지 않은 상태가 없으므로 옵션 3은 /api/posts/[postId].js
를 사용하는 것은 유효하지 않습니다. 어떤 상황에서도 GET api/posts
는 /api/posts/[postId].js
와 일치하지 않습니다.
API 라우트는 괄호 안에 세 개의 점 (...
)을 추가하여 모든 경로를 캐치할 수 있습니다. 예를 들어:
pages/api/post/[...slug].js
는 /api/post/a
에 대해 일치하지만, /api/post/a/b
, /api/post/a/b/c
등도 일치합니다.
참고:
[...param]
과 같은slug
외의 이름도 사용할 수 있습니다.
일치하는 매개변수는 쿼리 매개변수(slug
)로 페이지로 전송되며 항상 배열입니다. 따라서 경로 /api/post/a
에는 다음과 같은 쿼리 객체가 있습니다.
{ "slug": ["a"] }
/api/post/a/b
및 일치하는 모든 경로의 경우 다음과 같이 새 매개변수가 배열에 추가됩니다.
{ "slug": ["a", "b"] }
pages/api/post/[...slug].js
에 대한 API
라우트는 다음과 같습니다.
export default function handler(req, res) {
const { slug } = req.query;
res.end(`Post: ${slug.join(', ')}`);
}
이제 /api/post/a/b/c
에 대한 요청은 다음과 같은 응답을 반환합니다: Post: a, b, c
.
파라미터를 더블 대괄호 안에 포함하여 캐치 올 라우트를 선택적으로 만들 수 있습니다([[...slug]]
).
예를 들어, pages/api/post/[[...slug]].js
는 /api/post
, /api/post/a
, /api/post/a/b
등과 일치합니다.
캐치 올 라우트와 선택적 캐치 올 라우트의 주요 차이점은 선택적인 경우, 파라미터가 없는 경로도 일치한다는 것입니다(위의 예에서 /api/post
경로도 일치합니다).
쿼리 객체는 다음과 같습니다:
{ } // GET `/api/post` (빈 객체)
{ "slug": ["a"] } // `GET /api/post/a` (요소가 하나인 배열)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (다중 요소 배열)
pages/api/post/create.js
- /api/post/create
에 일치합니다.pages/api/post/[pid].js
- /api/post/1, /api/post/abc
등에 일치합니다. 하지만 /api/post/create
에는 일치하지 않습니다.pages/api/post/[...slug].js
- /api/post/1/2
, /api/post/a/b/c
등에 일치합니다. 하지만 /api/post/create
, /api/post/abc
에는 일치하지 않습니다.예시:
API 라우트는 들어오는 요청(req
)을 구문 분석하는 내장된 요청 도우미를 제공합니다.
req.cookies
- 요청으로 전송된 쿠키를 포함하는 객체입니다. 기본값은 {}
req.query
- 쿼리 문자열을 포함하는 객체입니다. 기본값은 {}
req.body
- 콘텐츠 유형(content-type
)으로 구문 분석된 본문을 포함하는 객체 또는 본문이 전송되지 않은 경우 null
입니다.API Route마다 기본 구성을 변경할 수 있는 구성 객체를 내보낼 수 있습니다. 기본 구성은 다음과 같습니다.
export const config = {
api: {
bodyParser: {
sizeLimit: '1mb',
},
},
};
api 객체에는 API Routes
에서 사용 가능한 모든 구성 옵션이 포함됩니다.
bodyParser
는 자동으로 활성화됩니다. Stream
또는 raw-body로 본문을 소비하려면 이를 false
로 설정할 수 있습니다.
자동 bodyParsing
을 비활성화하는 경우 webhook
요청의 원시 본문을 확인할 수 있도록 할 수 있습니다(예: GitHub에서).
export const config = {
api: {
bodyParser: false,
},
};
bodyParser.sizeLimit
은 파싱된 본문의 최대 크기입니다. bytes
에서 지원하는 어떤 형식이든 사용할 수 있습니다.
export const config = {
api: {
bodyParser: {
sizeLimit: '500kb',
},
},
};
externalResolver
는이 라우트가 express
또는 connect
와 같은 외부 resolver
에 의해 처리되고 있음을 명시적으로 알리는 플래그입니다. 이 옵션을 활성화하면 미해결된 요청에 대한 경고가 비활성화됩니다.
export const config = {
api: {
externalResolver: true,
},
};
responseLimit
은 API Routes
의 응답 본문이 4MB
를 초과할 때 경고가 발생합니다.
서버리스 환경에서 Next.js를 사용하지 않으며 CDN
또는 전용 미디어 호스트를 사용하지 않을 경우 이 한도를 false
로 설정할 수 있습니다.
export const config = {
api: {
responseLimit: false,
},
};
responseLimit
는 bytes
에서 지원하는 바이트 수 또는 어떤 문자열 형식('500kb
' 또는 '3mb
'와 같은)이든 사용할 수 있으며, 경고가 표시되기 전에 최대 응답 크기가 됩니다. 기본값은 4MB
입니다. (위 참조)
더 나은 타입 안정성을 위해서는 req
와 res
객체를 확장하지 않는 것이 권장됩니다. 대신, 이러한 객체들을 다루기 위해 함수를 사용하세요:
// utils/cookies.ts
import { serialize, CookieSerializeOptions } from 'cookie';
import { NextApiResponse } from 'next';
/**
* This sets `cookie` using the `res` object
*/
export const setCookie = (
res: NextApiResponse,
name: string,
value: unknown,
options: CookieSerializeOptions = {}
) => {
const stringValue =
typeof value === 'object' ? 'j:' + JSON.stringify(value) : String(value);
if (typeof options.maxAge === 'number') {
options.expires = new Date(Date.now() + options.maxAge * 1000);
}
res.setHeader('Set-Cookie', serialize(name, stringValue, options));
};
// pages/api/cookies.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { setCookie } from '../../utils/cookies';
const handler = (req: NextApiRequest, res: NextApiResponse) => {
// Calling our pure function using the `res` object, it will add the `set-cookie` header
// Add the `set-cookie` header on the main domain and expire after 30 days
setCookie(res, 'Next.js', 'api-middleware!', { path: '/', maxAge: 2592000 });
// Return the `set-cookie` header so we can display it in the browser and show that it works!
res.end(res.getHeader('Set-Cookie'));
};
export default handler;
만약, 이러한 객체들이 확장되는 것을 피할 수 없다면, 추가 속성을 포함하는 자신만의 타입을 만들어야 합니다:
// pages/api/foo.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { withFoo } from 'external-lib-foo';
type NextApiRequestWithFoo = NextApiRequest & {
foo: (bar: string) => void;
};
const handler = (req: NextApiRequestWithFoo, res: NextApiResponse) => {
req.foo('bar'); // we can now use `req.foo` without type errors
res.end('ok');
};
export default withFoo(handler);
기억해야 할 점은, 코드가 withFoo()
를 export
에서 제거해도 여전히 컴파일 된다는 것입니다. 따라서 이 방법은 안전하지 않습니다.
서버 응답 객체 (res
로 약어로 줄여집니다)는 Express.js
와 비슷한 도우미 메서드 세트를 포함하고 있습니다. 이는 개발자 경험을 향상시키고 새 API 엔드포인트를 더 빠르게 만드는 데 도움이 됩니다.
포함된 도우미는 다음과 같습니다:
res.status(code)
- 상태 코드를 설정하는 함수입니다. code는 유효한 HTTP 상태 코드여야 합니다.res.json(body)
- JSON 응답을 보냅니다. body는 직렬화 가능한 객체여야 합니다.res.send(body)
- HTTP 응답을 보냅니다. body는 문자열, 객체 또는 버퍼일 수 있습니다.res.redirect([status,] path)
- 지정된 경로 또는 URL로 리디렉션합니다. status
는 유효한 HTTP 상태 코드여야 합니다. 지정되지 않으면, status
는 "307
" "임시 리디렉션(Temporary redirect
)"으로 기본값이 설정됩니다.res.revalidate(urlPath)
- getStaticProps
를 사용하여 페이지를 필요에 따라 다시 유효성 검사합니다. urlPath
는 문자열이어야 합니다.클라이언트로 응답을 보낼 때, 응답의 상태 코드를 설정할 수 있습니다.
다음 예제는 응답의 상태 코드를 200
(정상)으로 설정하고 JSON
응답으로 message
속성을 반환합니다.
export default function handler(req, res) {
res.status(200).json({ message: 'Hello from Next.js!' });
}
클라이언트로 응답을 보낼 때, 직렬화 가능한 객체를 포함하는 JSON
응답을 보낼 수 있습니다. 실제 애플리케이션에서는 요청된 엔드포인트 결과에 따라 요청 상태를 클라이언트에 알릴 수 있습니다.
다음 예제는 비동기 작업의 결과와 함께 상태 코드 200
(정상)을 가진 JSON
응답을 보냅니다. try-catch
블록으로 처리하며, 적절한 상태 코드와 오류 메시지를 클라이언트에 반환합니다.
export default async function handler(req, res) {
try {
const result = await someAsyncOperation();
res.status(200).json({ result });
} catch (err) {
res.status(500).json({ error: 'failed to load data' });
}
}
HTTP
응답을 보내는 것은 JSON
응답을 보낼 때와 같이 작동합니다. 유일한 차이점은 응답 본문이 문자열, 객체 또는 버퍼일 수 있다는 것입니다.
다음 예제는 상태 코드가 200
(OK
) 이고 async
작업의 결과를 가진 HTTP
응답을 보냅니다.
export default async function handler(req, res) {
try {
const result = await someAsyncOperation();
res.status(200).send({ result });
} catch (err) {
res.status(500).send({ error: 'failed to fetch data' });
}
}
특정 경로 또는 URL
로 리디렉션
양식을 예로 들면, 양식이 제출되면 클라이언트를 지정된 경로 또는 URL
로 리디렉션 할 수 있습니다.
다음 예제는 양식이 성공적으로 제출되면 클라이언트를 /
경로로 리디렉션합니다.
export default async function handler(req, res) {
const { name, message } = req.body;
try {
await handleFormInputAsync({ name, message });
res.redirect(307, '/');
} catch (err) {
res.status(500).send({ error: 'failed to fetch data' });
}
}
response
핸들러를 더욱 안전한 타입으로 만들 수 있습니다. NextApiRequest
및 NextApiResponse
타입을 next
에서 가져온 후, response
데이터에도 타입을 지정할 수 있습니다.
import type { NextApiRequest, NextApiResponse } from 'next';
type ResponseData = {
message: string;
};
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.status(200).json({ message: 'Hello from Next.js!' });
}
참고: NextApiRequest
의 body
는 클라이언트가 임의의 페이로드를 포함시킬 수 있으므로 any
입니다. 사용하기 전에 실행 시간에 body
의 유형/구조를 검증해야 합니다.
타입을 사용한 더 많은 예제는 TypeScript
문서를 확인하십시오.
실제 프로젝트 구조 내에서 예제를 보려면 예제 저장소를 확인할 수 있습니다.
Edge API Routes
를 사용하면 Next.js를 사용하여 고성능 API를 구축할 수 있습니다. Edge Runtime
을 사용하여 Node.js 기반 API Routes
보다 빠릅니다. 이 성능 향상은 기본적으로 웹 API를 사용하므로 Native Node.js API
에 액세스할 수 없는 제약 사항이 있습니다.
폴더 pages/api
내부의 모든 파일은 /api/*
에 매핑되어 페이지 대신 API 엔드포인트로 처리됩니다. 이는 서버 사이드에서만 번들로 작동하며 클라이언트 사이드 번들 크기를 늘리지 않습니다.
export const config = {
runtime: 'edge',
};
export default (req) => new Response('Hello world!');
import type { NextRequest } from 'next/server';
export const config = {
runtime: 'edge',
};
export default async function handler(req: NextRequest) {
return new Response(
JSON.stringify({
name: 'Jim Halpert',
}),
{
status: 200,
headers: {
'content-type': 'application/json',
},
}
);
}
import type { NextRequest } from 'next/server';
export const config = {
runtime: 'edge',
};
export default async function handler(req: NextRequest) {
return new Response(
JSON.stringify({
name: 'Jim Halpert',
}),
{
status: 200,
headers: {
'content-type': 'application/json',
'cache-control': 'public, s-maxage=1200, stale-while-revalidate=600',
},
}
);
}
import type { NextRequest } from 'next/server';
export const config = {
runtime: 'edge',
};
export default async function handler(req: NextRequest) {
const { searchParams } = new URL(req.url);
const email = searchParams.get('email');
return new Response(email);
}
import { type NextRequest } from 'next/server';
export const config = {
runtime: 'edge',
};
export default async function handler(req: NextRequest) {
const authorization = req.cookies.get('authorization')?.value;
return fetch('https://backend-api.com/api/protected', {
method: req.method,
headers: {
authorization,
},
redirect: 'manual',
});
}
배포 시 특정 지역에만 edge function을 제한하려면 다음과 같이 할 수 있습니다.
참고: 이 설정은 Next.js v12.3.2 이상에서 사용할 수 있습니다.
import { NextResponse } from 'next/server';
export const config = {
regions: ['sfo1', 'iad1'], // 기본값은 'all'입니다.
};
export default async function handler(req: NextRequest) {
const myData = await getNearbyData();
return NextResponse.json(myData);
}
Edge API Routes
는 Edge Runtime
을 사용하고, API Routes
는 Node.js Runtime
을 사용합니다.
Edge API Routes
는 서버에서 응답을 스트리밍하고 캐시된 파일 (예: HTML
, CSS
, JavaScript
)에 액세스한 후 실행됩니다. 서버 측 스트리밍은 더 빠른 Time To First Byte
(TTFB
)로 성능을 향상시킬 수 있습니다.
참고:
getServerSideProps
와Edge Runtime
을 함께 사용하면 응답 객체에 액세스할 수 없습니다. 응답 객체에 액세스해야하는 경우 runtime: 'nodejs
'로Node.js Runtime
을 사용해야합니다.
Edge Runtime에서 지원되는 API 및 지원되지 않는 API를 확인하려면 다음 문서를 참조하십시오.