API Routes
Examples
Good to know : App Router를 사용하는 경우, API Routes 대신 Server Components 또는 Route Handlers 를 사용할 수 있습니다.
API routes는 Next.js로 공용 API 를 구축할 수 있는 솔루션을 제공합니다.
pages/api 폴더 내부의 모든 파일은 /api/*로 매핑되어 page 대신 API 엔드포인트로 처리됩니다. 이러한 파일들은 서버 사이드 번들로만 존재하며, 클라이언트 사이드 번들 크기를 증가시키지 않습니다.
예를 들어, 다음 API 라우트는 상태 코드 200과 함께 JSON 응답을 반환합니다:
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!' })
}export default function handler(req, res) {
res.status(200).json({ message: 'Hello from Next.js!' })
}Good to know:
- API Routes는 기본적으로 동일 출처 만 허용하며, CORS 헤더를 지정하지 않습니다 (opens in a new tab) . 이러한 동작은 CORS 요청 도우미 (opens in a new tab) 로 요청 핸들러를 감싸서 사용자 정의할 수 있습니다.
- API Routes는 정적 내보내기 와 함께 사용할 수 없습니다. 그러나 App Router의 Route Handlers 를 사용할 수 있습니다.
- API Routes는
next.config.js의 pageExtensions 설정 의 영향을 받습니다.
- API Routes는
Parameters
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// ...
}req: http.IncomingMessage (opens in a new tab) 인스턴스res: http.ServerResponse (opens in a new tab) 인스턴스
HTTP Methods
API 라우트에서 다양한 HTTP 메서드를 처리하려면 요청 핸들러에서 req.method를 사용할 수 있습니다. 예:
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
// POST 요청 처리
} else {
// 다른 HTTP 메서드 처리
}
}export default function handler(req, res) {
if (req.method === 'POST') {
// POST 요청 처리
} else {
// 다른 HTTP 메서드 처리
}
}Request Helpers
API Routes는 들어오는 요청(req)을 구문 분석하는 내장 요청 도우미를 제공합니다:
req.cookies- 요청에 의해 전송된 쿠키를 포함하는 객체. 기본값은{}req.query- 쿼리 문자열 (opens in a new tab) 을 포함하는 객체. 기본값은{}req.body-content-type에 따라 구문 분석된 body를 포함하는 객체, body가 전송되지 않은 경우null
Custom config
모든 API 라우트는 기본 설정을 변경하기 위해 config 객체를 내보낼 수 있습니다. 기본 설정은 다음과 같습니다:
export const config = {
api: {
bodyParser: {
sizeLimit: '1mb',
},
},
// 이 함수가 실행되는 최대 허용 시간을 지정함 (초 단위)
maxDuration: 5,
}bodyParser는 자동으로 활성화됩니다. body를 Stream으로 소비하거나 raw-body (opens in a new tab) 로 소비하려면 이를 false로 설정할 수 있습니다.
자동 bodyParsing을 비활성화하는 한 가지 사용 사례는 예를 들어 GitHub (opens in a new tab) 웹훅 요청의 원본 body를 확인할 수 있도록 하는 것입니다.
export const config = {
api: {
bodyParser: false,
},
}bodyParser.sizeLimit은 bytes (opens in a new tab) 가 지원하는 형식으로 구문 분석된 body의 최대 크기입니다. 예를 들어:
export const config = {
api: {
bodyParser: {
sizeLimit: '500kb',
},
},
}externalResolver는 이 라우트가 express 또는 connect와 같은 외부 리졸버에 의해 처리되고 있음을 서버에 명시적으로 알리는 플래그입니다. 이 옵션을 활성화하면 해결되지 않은 요청에 대한 경고가 비활성화됩니다.
export const config = {
api: {
externalResolver: true,
},
}responseLimit는 자동으로 활성화되며, API 라우트의 응답 body가 4MB를 초과할 경우 경고가 표시됩니다.
서버리스 환경에서 Next.js를 사용하지 않고, CDN이나 전용 미디어 호스트를 사용하지 않는 경우의 성능 영향을 이해하는 경우, 이 제한을 false로 설정할 수 있습니다.
export const config = {
api: {
responseLimit: false,
},
}responseLimit은 또한 bytes에서 지원하는 형식의 바이트 수 또는 문자열 형식을 취할 수 있습니다. 예를 들어 1000, '500kb' 또는 '3mb' 등이 있습니다.
이 값은 경고가 표시되기 전에 응답 크기의 최대값입니다. 기본값은 4MB입니다. (위 참조)
export const config = {
api: {
responseLimit: '8mb',
},
}Response Helpers
서버 응답 객체 (opens in a new tab) (종종 res로 약칭됨)에는 개발자 경험을 개선하고 새로운 API 엔드포인트를 생성하는 속도를 높이기 위한 Express.js와 유사한 도우미 메서드 세트가 포함되어 있습니다.
포함된 도우미는 다음과 같습니다:
res.status(code)- 상태 코드를 설정하는 함수.code는 유효한 HTTP 상태 코드 (opens in a new tab) 여야 합니다res.json(body)- JSON 응답을 보냅니다.body는 직렬화 가능한 객체 (opens in a new tab) 여야 합니다res.send(body)- HTTP 응답을 보냅니다.body는string,object또는Buffer일 수 있음res.redirect([status,] path)- 지정된 경로 또는 URL로 리디렉션합니다.status는 유효한 HTTP 상태 코드 (opens in a new tab) 여야 하며, 지정되지 않으면 기본값은 "307" "임시 리디렉션"입니다.res.revalidate(urlPath)-getStaticProps를 사용하여 페이지를 필요에 따라 재검증 합니다.urlPath는string이어야 합니다.
Setting the status code of a response
클라이언트에 응답을 보낼 때 응답의 상태 코드를 설정할 수 있습니다.
다음 예제는 응답의 상태 코드를 200 (OK)으로 설정하고 Hello from Next.js! 값의 message 프로퍼티와 함께 JSON 응답을 반환합니다:
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!' })
}export default function handler(req, res) {
res.status(200).json({ message: 'Hello from Next.js!' })
}Sending a JSON response
클라이언트에 응답을 보낼 때 JSON 응답을 보낼 수 있습니다. 이는 직렬화 가능한 객체 (opens in a new tab) 여야 합니다. 실제 애플리케이션에서는 요청된 엔드포인트의 결과에 따라 요청의 상태를 클라이언트에 알리고자 할 수 있습니다.
다음 예제는 상태 코드 200 (OK)와 비동기 작업의 결과를 포함한 JSON 응답을 보냅니다. 오류가 발생할 수 있는 상황을 처리하기 위해 try catch 블록에 포함되어 있으며, 적절한 상태 코드와 함께 잡힌 오류 메시지를 클라이언트에 다시 보냅니다:
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
try {
const result = await someAsyncOperation()
res.status(200).json({ result })
} catch (err) {
res.status(500).json({ error: '데이터를 불러오는 데 실패했습니다.' })
}
}export default async function handler(req, res) {
try {
const result = await someAsyncOperation()
res.status(200).json({ result })
} catch (err) {
res.status(500).json({ error: '데이터를 불러오는 데 실패했습니다.' })
}
}Sending a HTTP response
HTTP 응답을 보내는 것은 JSON 응답을 보내는 것과 동일하게 작동합니다. 유일한 차이점은 응답 body가 string, object 또는 Buffer일 수 있다는 것입니다.
다음 예제는 상태 코드 200 (OK)와 비동기 작업의 결과를 포함한 HTTP 응답을 보냅니다.
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
try {
const result = await someAsyncOperation()
res.status(200).send({ result })
} catch (err) {
res.status(500).send({ error: '데이터를 가져오는 데 실패했습니다' })
}
}export default async function handler(req, res) {
try {
const result = await someAsyncOperation()
res.status(200).send({ result })
} catch (err) {
res.status(500).send({ error: '데이터를 가져오는 데 실패했습니다' })
}
}Redirects to a specified path or URL
양식을 예로 들어, 양식을 제출한 후 클라이언트를 지정된 경로 또는 URL로 리디렉션하고자 할 수 있습니다.
다음 예제는 양식이 성공적으로 제출되면 클라이언트를 / 경로로 리디렉션합니다:
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const { name, message } = req.body
try {
await handleFormInputAsync({ name, message })
res.redirect(307, '/')
} catch (err) {
res.status(500).send({ error: '데이터를 가져오는 데 실패했습니다' })
}
}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: '데이터를 가져오는 데 실패했습니다' })
}
}Adding TypeScript types
NextApiRequest 및 NextApiResponse 타입을 next에서 가져와 API Routes를 더 타입 안정적으로 만들 수 있습니다. 추가로, 응답 데이터도 타입 지정할 수 있습니다:
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!' })
}Good to know :
NextApiRequest의 body는any입니다. 이는 클라이언트가 임의의 페이로드를 포함할 수 있기 때문입니다. body를 사용하기 전에 런타임에서 body의 타입/형태를 검증해야 합니다.
Dynamic API Routes
API Routes는 dynamic routes 를 지원하며, pages/에 사용된 파일 명명 규칙을 따릅니다.
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const { pid } = req.query
res.end(`Post: ${pid}`)
}export default function handler(req, res) {
const { pid } = req.query
res.end(`Post: ${pid}`)
}이제 /api/post/abc로의 요청은 Post: abc라는 텍스트로 응답합니다.
Catch all API routes
API Routes는 괄호 안에 세 개의 점(...)을 추가하여 모든 경로를 포착하도록 확장할 수 있습니다. 예:
pages/api/post/[...slug].js는/api/post/a와 일치하지만,/api/post/a/b,/api/post/a/b/c등과도 일치합니다.
Good to know :
slug외에도[...param]과 같은 이름을 사용할 수 있습니다.
일치하는 매개변수는 페이지에 쿼리 매개변수로 전송되며(예제에서는 slug), 항상 배열 형태로 전송됩니다. 따라서 /api/post/a 경로는 다음과 같은 query 객체를 가집니다:
{ "slug": ["a"] }그리고 /api/post/a/b 및 다른 일치하는 경로의 경우, 새로운 매개변수가 배열에 추가됩니다. 예:
{ "slug": ["a", "b"] }예를 들어:
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const { slug } = req.query
res.end(`Post: ${slug.join(', ')}`)
}export default function handler(req, res) {
const { slug } = req.query
res.end(`Post: ${slug.join(', ')}`)
}이제 /api/post/a/b/c로의 요청은 Post: a, b, c라는 텍스트로 응답합니다.
Optional catch all API routes
모든 경로 포착 라우트를 선택적 포착 라우트로 만들려면 매개변수를 이중 괄호([[...slug]])에 포함합니다.
예를 들어, pages/api/post/[[...slug]].js는 /api/post, /api/post/a, /api/post/a/b 등과 일치합니다.
모든 경로 포착 라우트와 선택적 모든 경로 포착 라우트의 주요 차이점은 매개변수 없이도 경로가 일치한다는 점입니다(위 예제에서는 /api/post).
query 객체는 다음과 같습니다:
{ } // `GET /api/post` (빈 객체)
{ "slug": ["a"] } // `GET /api/post/a` (단일 요소 배열)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (다중 요소 배열)Caveats
- 미리 정의된 API 라우트는 동적 API 라우트보다 우선하며, 동적 API 라우트는 모든 경로 포착 API 라우트보다 우선합니다. 다음 예제를 참조하세요:
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와는 일치하지 않습니다.
Edge API Routes
API Routes를 Edge Runtime과 함께 사용하고자 하는 경우, 점진적으로 App Router를 도입하고 Route Handlers 를 사용하는 것을 권장합니다.
Route Handlers 함수 시그니처는 isomorphic으로, Edge와 Node.js 런타임 모두에 동일한 함수를 사용할 수 있습니다.