API Routes

Intro

pages/api 안에 있는 어떤 파일이든 전부 /api/*/로 접근 할 수 있으며, page 대신 API 최종점으로 여겨진다. 이 API들은 전부 server-side 전용이며, Client-side의 번들 사이즈를 증가시키지는 않는다.

예를들어, 다음과 같이 pages/api/users.js가 리턴하는 json같응ㄴ 경우는 status 200으로 소통한다.

export default function handler(req, res) {
  res.status(200).json({ name: "YeongGi Yoon" });
}

이러한 API route가 작동하려면, 함수를 default 로 export 해야하며, 다음과 같은 인자들을 받는다

  • req: http.IncomingMessage의 객체 중 하나 + pre-built middleware
  • res: http.ServerResponse의 객체 중 하나 + helper functions

다양한 HTTP API route를 처리하기 위해, request handler에 다음과 같이 req.method를 활용할 수 있다.

export default function handler(req, res) {
	if (req.method === 'POST) {
		//POST에 해당하는 req
	}
	else {
		//그 외
	}
}

Use Cases

새로운 프로젝트들을 위해서, 모든 API 와 API route를 만들 수 있다. 만약 존재하는 API가 있따면, API Route를 통한 forward call을 하지 않아도 된다. 다양한 API Route의 활용법은 다음과 같다.

  • 외부 서비스의 URL를 마스킹 하는것 (https://company.com/secret-url 대신 /api/secret을 사용하게 하는 것)
  • 서버에서 환경변수를 사용하여 더욱 안전하게 외부 서비스를 접근하는 법

Caveats

API Routes는 CORS header를 특정화하지 않는다. 즉, 일반적으로 같은 근간이라 할 수 있다. 이와같은 행동은 CORS middleware에서 정의 할 수 있다. API Route는 next export와 같이 사용될 수 없다.

Dynamic API Routes

API Route같은 경우에 Dynamic Routes를 바로 지원하며, 즉 pages 안에 파일 이름 규칙이 있다면 가져 올 수 있다. 예를들어 pages/api/post/[pid].js 와 같은 API Route가 존재한다면 코드로는 다음과 같다.

export default function handler(req, res) {
  const { pid } = req.query;
  res.end(`Post: ${pid}`);
}

이렇게 되면, /api/post/abc에 해당하는 request가 Post: abc에서 응답을 받을 수 있다.

RESTful한 방식으로 routes를 만들면 다음과 같다.

  • GET api/posts : 모든 포스트에 대한 list를 가져온다
  • GET api/posts/12345 : 12345에 대한 포스트 정보만 가져온다

그럼 모델을 두가지 분류로 나눌 수 있다.

  1. 1번 옵션
    • /api/posts.js
    • /api/posts/[postId].js
  2. 2번 옵션
    • /api/posts/index.js
    • /api/posts/[postId].js

두가지 다 동일하지만, 세번째 옵션 /api/posts/[postId].js 같은 경우에는 Dynamic Routes가 undefined한 상태가 없기에 유효하지 않다.

Catch all API routes

API Route는 ...을 추가하여 모든 루트를 추가할 수 있다. 예를 들어 pages/api/post/[...slug].js/api/post/a와 매칭되며, /api/post/a/b/api/post/a/b/c 모두 매칭이 된다. 이렇게 매칭된 인자들은 query parameter로 넘겨지며, 항상 배열이 된다. 즉 /api/post/a라는 루트는 { "slug": ["a"]} 라는 query object를 가지게 된다. 만약 /api/post/a/b 라면 { "slug": ["a", "b"]} 처럼 가지게 된다.

종합하여 보면 pages/api/post/[...slug].js 라는 API Route 는 다음과 같이 생겼다.

export default function handler(req, res) {
  const { slug } = req.query;
  res.end(`Post: ${slug.join(", ")}`);
}

그럼 /api/post/a/b/c 라는 request는 Post: a, b, c로 응답을 받게된다.

Optional catch all API routes

이중괄후를 사용하여 모든 루트를 찾는 방법또한 사용 할 수 있다. [[...slug]] 처럼 사용하면 되며 pages/api/post[[...slug]].js/api/post/api/post/a/api/post/a/b 모두 매칭 된다고 볼 수 있다.

Caveats

  • 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 Middlewares

Response Helpers