[Next.js] APIs 생성하기

문지은·2024년 1월 8일
1

Next.js - App Router

목록 보기
6/20
post-thumbnail

Next.js는 내장된 API 엔드포인트 기능을 제공한다.

이는 별도의 서버를 만들지 않고, Next.js 앱 내부에서 HTTP 요청과 응답을 처리할 수 있는 기능을 제공한다.

API는 app 폴더 안에 api 폴더를 만들어 폴더 내에 파일을 정의해서 사용한다.
API 폴더 컨벤션은 필수적이지는 않지만, API 엔드포인트의 그룹화와 체계적인 관리에 유용하다.

Next.js 에서 API 엔드포인트를 구축하는 방법에 대해 알아보자.

HTTP 메소드와 상태 코드

  • HTTP 요청에는 GET(데이터 가져오기), POST(데이터 생성), PUT/PATCH(데이터 업데이트), DELETE(데이터 삭제)와 같은 메소드가 있다.
  • HTTP 프로토콜은 다양한 상황에 대한 표준 상태 코드를 정의한다. 흔히 사용되는 상태 코드로는 200(성공), 201(자원 생성됨), 400(잘못된 요청), 404(찾을 수 없음), 500(내부 서버 오류) 등이 있다.

객체 컬렉션 가져오기 (GET)

route.tsx

  • 라우트 파일을 생성하면, 앱 폴더를 제외한 특정 URL로 요청이 가능해진다.
    • ex) app/api/users/route.tsxlocalhost:3000/api/users
    • 이러한 방식은 서버의 라우트 기능과 유사하게 작동한다.
    • 한 폴더 내에서 route.tsx 파일과 page.tsx 파일이 동시에 존재할 수 없다.
  • Next.js 에서 지정한 파일명이기 때문에 반드시 지켜야 한다.
  • route.tsx 파일 내에서 HTTP 메소드명을 함수 이름으로 지정하면, 해당 함수가 그 메소드에 대한 요청을 처리하게 된다.
    • 예를 들어, GET 요청을 처리하려면 함수 이름을 GET으로 지정하면 된다.
    • 그 후로 해당 URL로 GET 요청을 보내면 이 함수가 그 요청을 처리하게 된다.

GET 요청을 처리하는 함수를 만들어보자.

  • 먼저 app 폴더 내에 api 폴더를 생성한다.
    • 그 안에 users 폴더를 생성하고 폴더 내에 route.tsx 파일을 생성해보자.
  • Request and Response
    • GET 요청을 처리하는 함수를 라우트 파일 내에 생성한다.
    • next/server에서 제공하는 [NextRequest](https://nextjs.org/docs/app/api-reference/functions/next-request) 타입을 인자로 사용한다.
      • GET 핸들러에 인자값이 없는 경우, 응답 결과를 캐싱한다.
    • 응답 처리에는 next/server[NextResponse](https://nextjs.org/docs/app/api-reference/functions/next-response) 메소드를 활용한다.
    • 응답 데이터로는 배열을 선택하여 전달한다.
    • 전달되는 데이터 배열은 최종적으로 JSON 형태로 반환된다.
  • 다양한 메소드로의 요청을 처리하기 위해 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" },
  ]);
}
  • Postman 에서 localhost:3000/api/users 로 GET 요청을 보낸 후 응답 결과를 확인해보자.
    • 결과가 잘 출력되는 것을 확인할 수 있다.

단일 객체 가져오기 (GET)

  • 이번에는 GET 메소드와 Dynamic Routes 를 함께 사용하는 방법에 대해 알아보자.
  • Dynamic Routes 는 다음과 같이 고정된 URL에 동적으로 변하는 변수를 처리할때 사용한다.
    • Folder Structure : app/users/[id]/page.tsx
    • URL : localhost:3000/users/1, localhost:3000/users/2, localhost:3000/users/3
  • 마찬가지로 동적으로 변하는 매개변수를 처리하는 API를 만들고 싶을 경우, 다음과 같이 폴더를 구성할 수 있다.
    • Folder Structure : app/api/users/[id]/route.tsx
  • 생성한 동적 매개변수 폴더에 routes.tsx 파일을 만들고 GET 메소드 핸들러 함수를 정의해보자.
    • 매개변수 첫 번째 인자로는 request를 두 번째 인자로는 params를 추가하면 된다.
    • props 내에 동적 매개 변수에 접근할 수 있는 params 속성을 추출하여, 사용자 정보를 응답으로 전달하도록 작성
    • 사용자 정보가 없는 경우 404 에러 반환

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);
}
  • Postman에서 정상 작동 확인

  • 사용자 정보가 없는 경우 404 에러와 함께 오류 메시지 출력

객체 생성하기 (POST)

  • 이번에는 객체를 생성할 때 사용하는 POST 메서드 핸들러를 만들어보자.
  • 이전에 사용자 정보 GET 메소드를 만들었던 app/api/users/route.tsx 파일에 POST 메소드 핸들러를 작성해보자.
    • 함수명 POST는 Next.js 에서 식별하는 이름이기 때문에, 다른 이름을 사용해서는 안된다.

request.json()

  • 요청으로 들어온 JSON 형태의 데이터를 추출할 때 사용
    • POST 메서드는 요청과 함께 데이터를 추출해야 하기 때문에 NextRequest 에서 사용하는 json 메서드를 사용한다.
  • 프로미스를 리턴하기 때문에 async/await 과 함께 사용 가능
  • 현재는 Database를 사용하지 않고 있기 때문에, 요청 정보로 만든 객체만 반환하도록 코드를 작성해보자.

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 });
}
  • Postman을 사용해 테스트 해본 결과, 잘 작동하는 것을 볼 수 있다.

객체 업데이트하기 (PUT)

  • 이번에는 정보를 업데이트할 때 사용하는 PUT 메소드를 사용해보자.
  • PUT 메소드가 사용되는 상황은 다음과 같다.
    • 개별 사용자를 나타내는 엔드포인트에 업데이트하고 싶은 데이터를 전달하면 PUT 메소드는 전달받은 데이터를 업데이트 한다.
  • HTTP에는 업데이할 때 사용할 수 있는 두 가지 메소드가 존재한다.
    • PUT : 전체 데이터를 새로운 것그오 교체할 때 사용
    • PATCH : 데이터의 일부분만 수정할 때 사용
  • PUT 메소드를 직접 사용해보자.
    • app/api/users/[id]/route.tsxPUT이라는 이름의 함수를 작성한다.
      • Next.js 에서 명시한 이름이기 때문에 반드시 이 이름을 사용해야한다.
    • 요청과 함께 들어온 데이터를 추출해야 하기 때문에 NextRequest에서 사용하는 json 메소드를 사용한다.
      • Promise 를 리턴하기 때문에 async /await 으로 키워드를 작성
  • json 메소드로 요청한 데이터를 확인하고, 사용자 이름을 변경시켜주는 함수를 작성
    • 만약 데이터가 존재하지 않는 경우 404 에러를 응답
    • 요청 데이터에 이름을 포함시키지 않아도 404 에러를 응답
    • 아직 데이터베이스를 연결하지 않았으므로, 변경시킨 객체만을 반환하도록 작성

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 });
}
  • Postman으로 테스트 해보면, 요청 데이터를 전달하는 경우와 전달하지 않는 경우 모두 잘 처리하는 것을 확인할 수 있다.

객체 삭제하기 (DELETE)

  • 이번에는 정보를 삭제하는 DELETE 메소드를 사용해보자.
  • DELETE 메소드가 사용되는 상황은 다음과 같다.
    • 개별 사용자를 나타내는 엔드포인트에 DELETE 메소드로 요청을 전달하면, DELETE 메소드는 요청을 전달 받고 사용자 정보를 삭제한다.
  • 이전의 POST, PUT 메소드와 차이가 있다면 DELETE 메소드는 요청 데이터가 필요하지 않다는 점이다.
  • 이제 users 폴더의 다이나믹 라우트로 아이디를 처리하는 폴더의 라우트 파일에서 DELETE 메소드를 처리하는 라우터를 생성해보자.
    • 다른 메서드와 마찬가지로 삭제 함수 이름을 작성할 때는 Next.js 에서 지정한 DELETE 를 사용해야한다.
    • 이 경우 처리해야 할 데이터가 없기 때문에, 별도의 async/await 키워드가 필요하지는 않다.
    • 존재하지 않는 사용자의 경우 404 에러를 응답하도록 작성하고, 정상 작동할 경우 빈 객체를 반환하도록 작성한다.

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({});
}
  • Postman으로 테스트하면 삭제에 성공했을 경우 빈 객체를 잘 반환하는 것을 확인할 수 있다.

profile
코드로 꿈을 펼치는 개발자의 이야기, 노력과 열정이 가득한 곳 🌈

0개의 댓글