[Next.js] 데이터 조회/생성/수정/삭제 (CRUD) with Prisma Client

문지은·2024년 1월 22일
1

Next.js - App Router

목록 보기
10/20
post-thumbnail

Prisma client를 사용하여 데이터를 조회/생성/수정/삭제 하는 방법에 대해 알아보자.

데이터 조회하기(GET)

전체 데이터 조회하기

  • 이전 게시글에서 하드 코딩된 데이터를 반환했던 GET 함수를 데이터베이스에서 데이터를 가져오도록 수정해보자.

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" },
  ]);
}
  • 우선 불러올 데이터를 데이터베이스에 저장해야하는데, 아직 Post 함수 작성 전이므로, Mysql Workbench 에서 Sql 문을 작성하여 직접 데이터를 넣는다.
    • 필수 입력 값인 email, name 만 값을 작성하였고, 총 4개의 데이터를 작성하였다.
INSERT INTO mydb.User (email, name)
VALUES ('test@test.com', '문지은');
  • 데이터베이스 확인
SELECT * FROM mydb.User;

이제 Get 함수를 수정해보자.

  • Prisma 인스턴스를 가져온 후에, 모든 사용자를 가져오기 위해 findMany 메소드를 호출한다.
    • where 객체를 설정해 사용자를 필터링할 수 있고, xor 연산자를 통해 여러 조건을 결합할 수도 있다.
  • findMany 메소드 또한 promise 객체를 반환하기 때문에 async awiat 로 사용자를 가져온다.

app/api/users/route.tsx

import { NextRequest, NextResponse } from "next/server";
import prisma from "@/prisma/client";

export async function GET(request: NextRequest) {
  const users = await prisma.user.findMany();
  return NextResponse.json(users);
}
  • localhost:3000/api/usersGET 요청시 데이터를 잘 불러오는 것을 확인할 수 있다.

단일 데이터 조회하기

  • 이번에는 단일 사용자를 가져올 수 있도록 users/[id] 폴더의 route 파일을 수정해보자.
  • 마찬가지로 Prisma 인스턴스를 가져오고, 이번에는 findUnique 메소드를 사용한다.
    • 이 메소드는 단일 객체를 가져오는 함수로, 인자 값으로 조건을 설정할 수 있다.
    • 조건을 설정할 때는 where 속성을 사용한다.
    • URL 에서 추출할 수 있는 id param 값을 조건으로 설정해 특정 사용자 정보를 읽어오도록 작성한다.
    • 이 메소드 또한 promise를 리턴하므로 async await 을 적용한다.
    • 이 메소드는 존재하지 않는 사용자인 경우 오류 출력 대신에 null 값을 반환한다.

app/api/users/[id]/route.tsx

import { NextRequest, NextResponse } from "next/server";
import prisma from "@/prisma/client";

export async function GET(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  const requestedId = parseInt(params.id);

  const user = await prisma.user.findUnique({
    where: { id: requestedId },
  });

  return NextResponse.json(user);
}
  • localhost:3000/api/users/1 로 GET 요청 시 데이터를 잘 반환하는 것을 볼 수 있다.

  • 만약 존재하지 않는 데이터를 요청하면 오류 대신 null을 반환한다.

  • 존재하지 않는 데이터를 요청하면 오류를 반환하도록 코드 수정

app/api/users/[id]/route.tsx

import { NextRequest, NextResponse } from "next/server";
import prisma from "@/prisma/client";

export async function GET(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  const requestedId = parseInt(params.id);

  const user = await prisma.user.findUnique({
    where: { id: requestedId },
  });

  if (!user) {
    return NextResponse.json({ error: "USER NOT FOUND" }, { status: 404 });
  }

  return NextResponse.json(user);
}

데이터 생성하기(POST)

  • 이전에 작성했던 post 함수에서 schema를 이용한 요청 데이터 검증 로직을 추가하고 오류가 발생하지 않은 경우 데이터를 생성하도록 코드를 수정해보자.
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 });
}
  • 데이터 생성을 구현하기 위해서는 Prisma의 create 메서드를 사용한다.
    • 생성하려는 데이터를 create 메서드 인자 값으로 전달하고, 전달할때는 data라는 속성을 사용한다.

app/api/users/route.tsx

import { NextRequest, NextResponse } from "next/server";
import prisma from "@/prisma/client";
import schema from "./schema";

export async function POST(request: NextRequest) {
  const body = await request.json();

  // 데이터 검증
  const validation = schema.safeParse(body);
  if (!validation.success) {
    return NextResponse.json(validation.error.errors, { status: 404 });
  }

  // 새로운 사용자 생성
  const newUser = await prisma.user.create({
    data: {
      name: body.name,
      email: body.email,
    },
  });

  return NextResponse.json(newUser);
}
  • Postman 에서 localhost:3000/api/users 로 Post 요청시 정상적으로 작동하는 것을 확인할 수 있다.

  • 동일한 값으로 재요청을 하면 500 에러가 발생한다.
    • 정의했던 User 모델의 email unique 제약사항 때문!

  • 생성 전에 먼저 findUnique 메소드를 통해 해당 사용자의 존재 유무를 검사하고, 존재하지 않는 경우에 create 메소드를 실행하도록 코드 수정

app/api/users/route.tsx

import { NextRequest, NextResponse } from "next/server";
import prisma from "@/prisma/client";
import schema from "./schema";

export async function POST(request: NextRequest) {
  const body = await request.json();

  // 데이터 검증
  const validation = schema.safeParse(body);
  if (!validation.success) {
    return NextResponse.json(validation.error.errors, { status: 404 });
  }

  const user = await prisma.user.findUnique({
    where: { email: body.email },
  });

  if (user) {
    return NextResponse.json({ error: "User already exists" }, { status: 400 });
  }

  // 새로운 사용자 생성
  const newUser = await prisma.user.create({
    data: {
      name: body.name,
      email: body.email,
    },
  });

  return NextResponse.json(newUser);
}
  • 다시 테스트해보면, 같은 정보로 재요청 하는 경우 사용자가 이미 존재한다는 오류 메세지를 응답으로 전달받게 된다.

데이터 업데이트하기 (PUT)

  • api/users/[id]/route.tsx 파일을 수정하여 데이터를 업데이트 하는 함수를 작성해보자.
  • 먼저, findUnique 메소드를 사용해 사용자 존재 여부를 검사하고, 사용자 객체가 존재하지 않으면 오류를 반환하고, 존재하는 경우 Prismaupdate 메소드를 사용해 데이터 업데이트를 진행한다.
  • update 메소드는 인자값으로 객체를 받는데, 객체 내부에는 where 속성을 사용해 찾고자 하는 데이터를 명시하고, data 속성에는 업데이트 하고자 하는 데이터를 명시할 수 있다.
    • 이 메소드 또한 promise 를 리턴하기 때문에 async await 을 적용한다.
  • 리턴 값으로는 업데이트된 객체를 반환한다.

app/api/users/[id]/route.tsx

import { NextRequest, NextResponse } from "next/server";
import prisma from "@/prisma/client";
import schema from "../schema";

export async function PUT(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  const body = await request.json();

  const validation = schema.safeParse(body);

  if (!validation.success) {
    return NextResponse.json(validation.error.errors, { status: 404 });
  }

  const requestedId = parseInt(params.id);

  const user = await prisma.user.findUnique({
    where: { id: requestedId },
  });

  if (!user) {
    return NextResponse.json({ error: "USER NOT FOUND" }, { status: 404 });
  }

  const uadatedUser = await prisma.user.update({
    where: { id: requestedId },
    data: { name: body.name, email: body.email },
  });

  return NextResponse.json(uadatedUser);
}
  • Postman에서 테스트해보면 잘 수정된 것을 확인할 수 있다.

  • 데이터베이스에도 잘 반영되었다.

데이터 삭제하기(DELETE)

  • api/users/[id]/route.tsx 파일을 수정하여 데이터를 삭제 하는 함수를 작성해보자.
  • 먼저, findUnique 메소드를 사용해 사용자 존재 여부를 검사하고, 사용자 객체가 존재하지 않으면 오류를 반환하고, 존재하는 경우 Prismadelete 메소드를 사용해 데이터 삭제를 진행한다.
  • 이 메소드는 객체를 인자로 전달받고 내부의 where 속성을 통해 삭제하고 싶은 객체의 정보를 명시할 수 있다.

app/api/users/[id]/route.tsx

import { NextRequest, NextResponse } from "next/server";
import prisma from "@/prisma/client";

export async function DELETE(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  const requestedId = parseInt(params.id);

  const user = await prisma.user.findUnique({
    where: { id: requestedId },
  });

  if (!user) {
    return NextResponse.json({ error: "USER NOT FOUND" }, { status: 404 });
  }

  await prisma.user.delete({ where: { id: requestedId } });

  return NextResponse.json({});
}
  • Postman에서 테스트해보자.

  • 삭제가 정상적으로 처리되어 데이터베이스에 잘 반영된 것을 볼 수 있다.

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

0개의 댓글