Post

Next.js 13의 특징과 변화(3) - API Routes

📌시작하며

이 글은 아래와 같이 이어집니다.

routes 부분도 12 버전과 달라진 부분이 꽤 있다! 헷갈리지 않도록 이 번엔 Next13의 API Routes🌹에 대해 알아보자.

✅API Routes

Next.js를 왜 쓰냐는 질문이 나오면 아마 API routes를 만들 수 있다는 것도 그 이유 중 하나일 것이다. 그래서 API routes가 뭘까? 공식 문서에서는 이렇게 설명한다.

API routes는 Next.js에서 public API를 만드는 역할을 한다.

API 라우트를 사용하면 Next.js 앱 내에서 API 엔드포인트를 만들 수 있으며, 이를 서버리스 함수로 배포할 수 있다.

정리하자면 서버리스 백엔드 엔드포인트를 만드는 것이다. 즉, Next,js를 이용해 RESTful API를 만들고 프론트엔드 개발자가 서버 측 코드를 작성해 간단하게 백엔드를 구축할 수 있다.

엔드포인트: 특정한 요청을 받아 처리하는 지점

✅기존 방식

1
2
3
pages/
  └─ api/
      └─ hello.ts 👈

기존에는 다음과 같은 폴더 구조에 api안의 js(ts)파일을 api endpoint로 취급했다. 또한 POST 방식이면 req.method 를 이용해 해당 방식이 POST 임을 조건문으로 처리한 후 작성해야 했다. 하지만 Next13은 좀더 직관적으로 작성할 수 있도록 변경되었다.

1
2
3
4
5
6
7
8
9
import type { NextApiRequest, NextApiResponse } from "next"

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === "POST") {
    // POST 요청에 관한 코드를 작성한다.
  } else {
    // POST가 아닌 다른 요청 처리
  }
}

✅새로운 방식

1
2
3
4
5
6
7
8
9
app/
│
└── api/
    │
    ├── firstApi/
    │   └── route.ts 👈
    │
    └── secondApi/
        └── route.ts 👈

먼저 폴더 구조가 변경되었다. app router 방식과 동일하게 폴더 구조를 취한다. api 폴더 안에 api의 특정한 이름을 가진 폴더를 만들고 routes.ts 파일을 만들어 작성한다.

function의 이름은 method 이름으로 작성한다.

1
2
3
4
5
6
7
8
export async function GET() {
  const res = await fetch("https://data.mongodb-api.com/...", {
    next: { revalidate: 60 }, // 60초마다 재실행
  })
  const data = await res.json()

  return Response.json(data)
}

✅body 받아오기

req.json() 을 이용해 받아온다.

1
2
3
4
export async function POST(req: Request) {
  //body 확인
  const { bodyText }: { bodyText: number } = await req.json()
}

✅쿼리스트링 받아오기

new URL(req.url) 을 이용해 받아온다.

1
2
3
4
5
6
7
import { type NextRequest } from "next/server"

export async function GET(req: NextRequest) {
  const { searchParams } = new URL(req.url)
  const page = searchParams.get("page") as string
  const count = searchParams.get("count") as string
}

.nextUrl.searchParams 을 이용해 받아올 수도 있다. (공식문서 설명)

1
2
3
4
5
6
7
import { type NextRequest } from "next/server"

export function GET(request: NextRequest) {
  const searchParams = request.nextUrl.searchParams
  const query = searchParams.get("query")
  // query is "hello" for /api/search?query=hello
}

✅formData 받아오기

request.formData()을 이용해 받아온다.

1
2
3
4
5
6
export async function POST(request: Request) {
  const formData = await request.formData()
  const name = formData.get("name")
  const email = formData.get("email")
  return Response.json({ name, email })
}

실제 formData를 사용하는 방식은 프로젝트 진행 하며 추가로 작성할 예정이다.

✅사용 예제

그럼 실제 사용 하는 방식을 총 정리해 살펴보자! 컴포넌트에서 다음과 같이 요청을 보낸다. axios의 기본 값은 GET 요청이므로 해당 요청은 GET 요청이며, 요청 url을 살펴보면 다음과 같은 폴더 구조의 route.ts에 요청을 보내고 있음을 알 수 있다.

1
2
3
4
5
6
app/
│
└── api/
    │
    └── hello/
        └── route.ts 👈

➡️GET 요청과 API routes

1
2
3
4
const fetchHello = async () => {
  const { data } = await axios(`/api/hello?id=${id}`)
  return data as HelloType
}
1
2
3
4
5
6
7
8
9
10
11
12
import { NextResponse } from "next/server"

export async function GET(req: NextResponse) {
  const { searchParams } = new URL(req.url)
  const id = searchParams.get("id") as string

  if (!id) {
    return NextResponse.json({ error: "id가 없습니다." }, { status: 400 })
  }

  return NextResponse.json(result, { status: 200 })
}

✅Cookies 사용하기

불러오는 방법에는 두 가지가 있다. 먼저 next/headers 로 불러오는 방식이다.

1
2
3
4
5
6
7
8
9
10
11
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.value}` },
  })
}

더 간단하게 NextRequest를 이용해 불러올 수 있다.

1
2
3
4
5
import { type NextRequest } from "next/server"

export async function GET(request: NextRequest) {
  const token = request.cookies.get("token")
}

✅Header 사용하기

Cookies와 동일하게 두 가지 방법으로 불러올 수 있다.

1
2
3
4
5
6
7
8
9
10
11
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 },
  })
}
1
2
3
4
5
import { type NextRequest } from "next/server"

export async function GET(request: NextRequest) {
  const requestHeaders = new Headers(request.headers)
}

✅NextResponse vs Response

위에서 살펴보면, 결과값을 NextResponse 혹은 Response 를 이용해 return 하는 것을 알 수 있다. 공부할 때 쭉 NextResponse를 사용하다보니 공식문서에 있는 Response를 보고 두 개의 차이점을 찾아보았다. 결론은 NextResponse가 Web Response를 확장한다는 것이다. 즉 특별하게 NextResponse를 사용해야 하는 경우가 아니라면 Response로 충분하다.

1
2
return NextResponse.json({ result: "결과값" }, { status: 200 })
return Response.json({ result: "결과값" }, { status: 200 })

📩마무리

app router의 폴더 구조를 이렇게 훑어보았다. 다음에는 api routes 작성법에 대해 살펴보자!

🗂️참고 사이트

This post is licensed under CC BY 4.0 by the author.