[Next.js] API Routes 공식 문서 정독

최익준·2023년 8월 25일
0

Next.js

목록 보기
4/7

Next.js API Routes

기본적으로 pages/api 폴더 안에서 바로 api를 구현할 수 있는 기능을 제공하고 있음.

pages/api/hello.ts에 다음 코드를 작성했다고 하면 ~~/api/hello로 접속했을 때 해당 api가 제공하는 정보를 받아볼 수 있다.

export default function handler(req, res) {
	res.status(200).json({ name: 'John Doe' })
}

공식 문서에서 말하기를, API route가 작동하기 위해서는 function을 default로 export해야한다. 이때 export되는 함수를 request handler라고 부르는 것 같다. 또한 request handler는 req, res를 파라미터로 불러와야한다.

다른 HTTP 메소드를 다루기 위해서는, req.method를 request handler에서 사용해주면 된다.

export default function handler(req,res) {
	if (req.method === 'POST') {
		// Process a POST request
	} else {
		// Handle and other HTTP method
	}
}

api를 Next Project 내부에서 사용할 경우 그냥 /api/파일명 형태로 입력해주면 된다.

Dynamic API Routes

api route도 dynamic routing을 지원한단다. 이것도 마찬가지로 파일명을 통해 구현할 수 있다.

pages/api/post/[pid].js

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

Catch all API routes

점 세 개를 찍으면 그 요소 안에 있는 모든 element에 대한 path에 모두 접근할 수 있다.

pages/api/post/[…slug].js → /api/post/a에도 접근할 수 있고, api/post/a/b에도 접근할 수 있고, api/post/a/b/c에도 접근할 수 있다.

url을 api/post/a/b라고 입력하면 slug은 { “slug”: [”a”, “b”] }와 같은 형태로 저장됨.

url을 api/post/a/b로 입력했을 경우

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

ㄹㅏ고 하면 Post : a, b, c라는 데이터가 출려됨.

Optional catch all API routes

모든 route를 catch하는 것을 선택적으로 하는 방법에 대한 설명이다.

→ 대괄호로 한 번 더 감싸면 된다.

[[…slug]]과 같은 형태로 사용하면 된다.

위에 있는 catch all과 다른 점은 매개 변수가 없는 경로도 일치한다는 점? 이다.

→ /api/post로만 입력했을 때. 즉, slug에 아무 데이터가 없을때도 동작한다!

{ } // GET `/api/post` (empty object)
{ "slug": ["a"] } // `GET /api/post/a` (single-element array)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (multi-element arra

API Routes Request Helpers

API Route는 내장 request helper를 제공한다.

  • req.cookies : request에 의해 보내진 쿠키를 나타내는 객체. 기본값은 {}
  • req.query : 쿼리문을 나타내는 객체. 기본값은 {}
  • req.body : content-type으로부터 받아온 body를 나타내는 객체. 아무 것도 없으면 null

Custom config

모든 API Route는 config object를 export할 수 있다. → 초기 상태를 바꾸고자 할 때 씀.

export const config = {
	api: {
		bodyParser: {
			sizeLimit: '1mb',
		}
	}
}

api 객체는 모든 config 옵션(API Route에서 사용가능 한)들을 포함한다.

bodyParser 는 자동으로 enabled되어있다. 원한다면 false 로 설정할 수 있음.

bodyParser를 false로 설정하는 예시 중 하나는 webhook request의 raw body를 확인하고자 할때?

export const config = {
	api: {
		bodyParser: false,
	},
}

bodyParser.sizeLimit는 parse된 body의 최대 사이즈를 설정해준다. 바이트 단위로 된 크기를 입력해주면 됨.

export const config = {
	api: {
		bodyParser: {
			sizeLimit: '500kb',
		},
	},
}

externalResolver는 이 route가 express 또는 connect와 같은 외부 resolver에 의해 처리되고 있음을 서버에 알리는 명시적 flag이다. 이 옵션을 활성화하면 확인되지 않은 요청에 대한 경고가 비활성화된다.

export const config = {
	api: {
		externalResolver: true,
	},
}

responseLimit 은 처음에는 자동으로 4MB로 설정되어있음.

만약 serverless 환경에서 Next.js를 사용하지 않고있고 CDN을 사용하지 않을 때의 퍼포먼스 영향을 이해하고 있다면, 이 제한을 false로 둘 수 있다.

export const config = {
	api: {
		responseLimit: false,
	},
}

responseLimit 도 또한 byte단위로 설정해줄 수 있다. false 자리에 ‘8mb’같은 문자열을 넣어주면 됨.

TypeScript로 req/res 객체 확장시키기

여기서 객체의 확장이라 함은 객체가 기본적으로 포함하고 있는 property에 새로운 property를 추가하는 것을 의미하는 것으로 보인다.

더 나은 type-safety를 위해서, req와 res 객체를 확정하는 것은 추천되지 않는다.

하지만 객체의 확장을 피할 수 없다면, 새로운 type을 새로 만들어야한다.

// 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');
	res.end('ok');
}

export default withFoo(handler)

API Routes Response Helpers

response 객체에는 Experss와 비슷한 helper메소드가 있다.

  • res.status(code) - status code 설정해주는 함수
  • res.json(body) - JSON response를 보냄. body 자리에는 반드시 serializable object가 들어가야 함
  • res.send(body) - HTTP response를 보냄. body는 문자열이나 객체가 들어갈 수 있음
  • res.redirect([status], path) - 특정 경로 혹은 url로 리다이렉트. status자리에는 HTTP status code가 들어감. default값은 307임 → Temporary redirect를 의미
  • res.revvalidate(urlPath) - Revalidate a page on demand using getStaticProps urlPath는 반드시 문자열 이어야 함. → “Revalidate a page on demand”는 차차 공부해보는 것으로 하자. → 캐시와 비슷한 의미인 것 같기도?

다음은 위 메소에 대한 예시 코드임.

Setting the status code of response

export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}

Sendeing a HTTP response

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' })
  }
}

Redirects to a specified path or 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' })
  }
}

Edge API Routes

Edge API Routes는 Next.js에서 High 퍼모먼스 API를 만들 수 있게 해준다.

Edge Runtime을 사용하면, 웬만한 Node.js 베이스의 API보다 속도가 빠르다.

(pages/api에 있는 모든 파일은 페이지가 아닌 API endpoint로 여겨진다. 이것은 server-side 번들이고 client-size 번들에 영향을 끼치지 않는다.

예시 코드

이렇게 설정해주면 edge runtime으로 사용할 수 있다.

export const config = {
  runtime: 'edge',
}

export default (req) => new Response('Hello world!')

json data 응답

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

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)
}

엣지 api route는 edge runtime을 사용해서 node.js 런타임을 사용한 api route보다 빠르다.

엣지 라우트는 서버로부터의 응답을 분산시키고 파일 캐시 이후에 실행된다.

server-side streaming은 Time to First Byte (TTFB)라는 기술을 사용해서 퍼포먼스를 좋게 만들 수 있다.

TTFB에 대해서는 나중에 공부해보도록 하자.

profile
공부하는 개발자 꿈나무

0개의 댓글