Next.js는 내장된 API 엔드포인트 기능을 제공한다.
이는 별도의 서버를 만들지 않고, Next.js 앱 내부에서 HTTP 요청과 응답을 처리할 수 있는 기능을 제공한다.
API는 app
폴더 안에 api
폴더를 만들어 폴더 내에 파일을 정의해서 사용한다.
API 폴더 컨벤션은 필수적이지는 않지만, API 엔드포인트의 그룹화와 체계적인 관리에 유용하다.
Next.js 에서 API 엔드포인트를 구축하는 방법에 대해 알아보자.
route.tsx
app/api/users/route.tsx
→ localhost:3000/api/users
route.tsx
파일과 page.tsx
파일이 동시에 존재할 수 없다.route.tsx
파일 내에서 HTTP 메소드명을 함수 이름으로 지정하면, 해당 함수가 그 메소드에 대한 요청을 처리하게 된다.GET
요청을 처리하려면 함수 이름을 GET
으로 지정하면 된다.GET
요청을 보내면 이 함수가 그 요청을 처리하게 된다.GET 요청을 처리하는 함수를 만들어보자.
app
폴더 내에 api
폴더를 생성한다.users
폴더를 생성하고 폴더 내에 route.tsx
파일을 생성해보자.next/server
에서 제공하는 [NextRequest](https://nextjs.org/docs/app/api-reference/functions/next-request)
타입을 인자로 사용한다.next/server
의 [NextResponse](https://nextjs.org/docs/app/api-reference/functions/next-response)
메소드를 활용한다.export default
대신 export
를 사용한다.app/api/users/route.tsx
import { NextRequest, NextResponse } from "next/server";
export function GET(request: NextRequest) {
return NextResponse.json([
{ id: 1, name: "a" },
{ id: 2, name: "b" },
]);
}
localhost:3000/api/users
로 GET 요청을 보낸 후 응답 결과를 확인해보자.app/users/[id]/page.tsx
localhost:3000/users/1
, localhost:3000/users/2, localhost:3000/users/3
app/api/users/[id]/route.tsx
routes.tsx
파일을 만들고 GET 메소드 핸들러 함수를 정의해보자.request
를 두 번째 인자로는 params
를 추가하면 된다.app/api/users/[id]/route.tsx
import { NextRequest, NextResponse } from "next/server";
export function GET(
request: NextRequest,
{ params }: { params: { id: string } }
) {
const userData = [
{ id: 1, name: "Jieun" },
{ id: 2, name: "Hansol" },
];
const requestedId = parseInt(params.id);
const user = userData.find((user) => user.id === requestedId);
if (!user) {
return NextResponse.json({ error: "USER NOT FOUND" }, { status: 404 });
}
return NextResponse.json(user);
}
app/api/users/route.tsx
파일에 POST 메소드 핸들러를 작성해보자.request.json()
async/await
과 함께 사용 가능app/api/users/route.tsx
import { NextRequest, NextResponse } from "next/server";
export async function POST(request: NextRequest) {
const body = await request.json();
// 요청한 데이터가 존재하지 않는다면 404 에러 반환
if (!body.name) {
return NextResponse.json({ error: "Name is required" }, { status: 404 });
}
if (!body.id) {
return NextResponse.json({ error: "Id is required" }, { status: 404 });
}
// 그렇지 않다면 전달 객체를 응답 객체로 반환
return NextResponse.json({ id: body.id, name: body.name });
}
PUT
메소드를 사용해보자.PUT
메소드가 사용되는 상황은 다음과 같다.PUT
메소드는 전달받은 데이터를 업데이트 한다.PUT
: 전체 데이터를 새로운 것그오 교체할 때 사용PATCH
: 데이터의 일부분만 수정할 때 사용app/api/users/[id]/route.tsx
에 PUT
이라는 이름의 함수를 작성한다.json
메소드를 사용한다.async
/await
으로 키워드를 작성json
메소드로 요청한 데이터를 확인하고, 사용자 이름을 변경시켜주는 함수를 작성app/api/users/[id]/route.tsx
import { NextRequest, NextResponse } from "next/server";
export async function PUT(
request: NextRequest,
{ params }: { params: { id: string } }
) {
const body = await request.json();
if (!body.name) {
return NextResponse.json({ error: "Name is Required" }, { status: 404 });
}
const userData = [
{ id: 1, name: "Jieun" },
{ id: 2, name: "Hansol" },
];
const requestedId = parseInt(params.id);
const user = userData.find((user) => user.id === requestedId);
if (!user) {
return NextResponse.json({ error: "USER NOT FOUND" }, { status: 404 });
}
return NextResponse.json({ id: requestedId, name: body.name });
}
DELETE
메소드가 사용되는 상황은 다음과 같다.DELETE
메소드로 요청을 전달하면, DELETE 메소드는 요청을 전달 받고 사용자 정보를 삭제한다.POST
, PUT
메소드와 차이가 있다면 DELETE
메소드는 요청 데이터가 필요하지 않다는 점이다.users
폴더의 다이나믹 라우트로 아이디를 처리하는 폴더의 라우트 파일에서 DELETE
메소드를 처리하는 라우터를 생성해보자.DELETE
를 사용해야한다.async
/await
키워드가 필요하지는 않다.app/api/users/[id]/route.tsx
import { NextRequest, NextResponse } from "next/server";
export async function DELETE(
request: NextRequest,
{ params }: { params: { id: string } }
) {
const userData = [
{ id: 1, name: "Jieun" },
{ id: 2, name: "Hansol" },
];
const requestedId = parseInt(params.id);
const user = userData.find((user) => user.id === requestedId);
if (!user) {
return NextResponse.json({ error: "USER NOT FOUND" }, { status: 404 });
}
return NextResponse.json({});
}