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 작성법에 대해 살펴보자!