๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
NestJS

NestJS์™€ prisma๋กœ ํŽธ๋ฆฌํ•˜๊ฒŒ CRUD ๊ตฌํ˜„ํ•˜๊ธฐ

by LasBe 2024. 11. 12.
๋ฐ˜์‘ํ˜•

๐Ÿ“’ NestJS๋กœ ํŽธ๋ฆฌํ•˜๊ฒŒ CRUD ๊ตฌํ˜„ํ•˜๊ธฐ


์š”์ฆ˜ NestJS๋ฅผ ์กฐ๊ธˆ์”ฉ ๊ณต๋ถ€ํ•˜๋ฉฐ ์ง„๋„๋ฅผ ๋‚˜๊ฐ€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฌ์šฉํ•  ์ˆ˜๋ก "์ •๋ง ํŽธ๋ฆฌํ•˜๋‹ค"๊ณ  ๋Š๋ผ๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ NestJS์™€ prisma๋กœ CRUD api๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ณผ์ •์„ ์†Œ๊ฐœ๋“œ๋ฆฌ๋ฉด์„œ ์–ด๋– ํ•œ ์ ์ด ํŽธ๋ฆฌํ–ˆ๋Š”์ง€ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ prisma ์„ค์น˜ ๊ณผ์ •

prisma๋ฅผ ์„ค์น˜ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์—ฐ๋™ํ•˜๋Š” ๊ณผ์ •์€ ๋‹ค์Œ ๊ธ€์— ์ž์„ธํžˆ ์†Œ๊ฐœ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

 

Docker๋กœ PostgreSQL ์„ค์น˜ํ•˜๊ณ  NestJS + prisma ์—ฐ๋™ํ•˜๊ธฐ

๐Ÿ“’  Docker๋กœ PostgreSQL ์„ค์น˜ํ•˜๊ณ  NestJS + prisma ์—ฐ๋™ํ•˜๊ธฐNestJS๋กœ ๊ฐœ๋ฐœํ•  ๋•Œ ์ฃผ๋กœ prisma์™€ postgresql์„ ์‚ฌ์šฉํ•˜๋Š” ์ถ”์„ธ์ž…๋‹ˆ๋‹ค.์™œ ์–ด๋– ํ•œ ํŠน์žฅ์ ์ด ์žˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์ดˆ๊ธฐ ์„ค์น˜ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ

lasbe.tistory.com

 

๐Ÿ“Œ prisma ์„ค์ •

src/prisma์— ์žˆ๋Š” prisma.service.ts์™€ prisma.module.ts์— ๋Œ€ํ•œ ์„ธํŒ…์„ ํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿ”Ž prisma.service.ts

import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService
  extends PrismaClient
  implements OnModuleInit, OnModuleDestroy
{
  async onModuleInit() {
    await this.$connect();
  }
  async onModuleDestroy() {
    await this.$disconnect();
  }
}
  • NestJS ๋ชจ๋“ˆ์ด ์ดˆ๊ธฐํ™”๋  ๋•Œ onModuleInit()์ด ํ˜ธ์ถœ๋˜์–ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ข…๋ฃŒ๋  ๋•Œ onModuleDestroy()๊ฐ€ ํ˜ธ์ถœ๋˜์–ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”Ž prisma.module.ts

import { Global, Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Global()
@Module({
  providers: [PrismaService],
  exports: [PrismaService],
})
export class PrismaModule {}

NestJS์—์„œ @Global ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํŠน์ • ๋ชจ๋“ˆ์„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ „์—ญ ๋ชจ๋“ˆ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ๋ชจ๋“ˆ์—์„œ ํ•ด๋‹น ๋ชจ๋“ˆ์„ ๋ฐ˜๋ณต์ ์œผ๋กœ imports๋ฌธ์— prisma ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ ์Šคํ‚ค๋งˆ ํ…Œ์ด๋ธ” ์ •์˜

// /prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id Int @default(autoincrement()) @id
  name String
}

model Post {
  id Int @default(autoincrement()) @id
  title String
  desc String
}

prisma/schema.prisma์—์„œ ํ…Œ์ด๋ธ”์„ ์ •์˜ํ•ด์ค๋‹ˆ๋‹ค.

์ €๋Š” ํ…Œ์ŠคํŠธ์šฉ์œผ๋กœ ์ •๋ง ๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์„ฑํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ prisma Client ์ƒ์„ฑํ•˜๊ธฐ  

$ npx prisma generate

prisma generate ๋ช…๋ น์–ด๋Š” Prisma Client๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ช…๋ น์–ด์ž…๋‹ˆ๋‹ค.

์ด ๋ช…๋ น์–ด๋Š” schema.prisma ํŒŒ์ผ์— ์ •์˜๋œ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ TypeScript ์ฝ”๋“œ๋กœ Prisma Client๋ฅผ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

์ƒ์„ฑ๋œ Prisma Client๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ CRUD ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์†Œ๋“œ๋“ค์„ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋งŒ์•ฝ $ npx prisma migrate dev์™€ ๊ฐ™์€ ๋ช…๋ น์–ด๋กœ DB์— ๋ฐ˜์˜์„ ํ–ˆ๋‹ค๋ฉด ์ž๋™์œผ๋กœ generate๊ฐ€ ์ˆ˜ํ–‰๋˜๋‹ˆ ๋”ฐ๋กœ ์•ˆํ•ด์ฃผ์…”๋„ ๋ฉ๋‹ˆ๋‹ค.

์„ฑ๊ณต์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์œผ๋ฉด ์œ„์™€ ๊ฐ™์ด ์ •์˜ํ•œ ํ…Œ์ด๋ธ”์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์—ฌ๋Ÿฌ ๋ฉ”์†Œ๋“œ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ”Ž ํด๋ผ์ด์–ธํŠธ์— ๋ฐ˜์˜์ด ์•ˆ๋  ๋•Œ

์Šคํ‚ค๋งˆ ์ •์˜ํ•˜๊ณ  prisma generate ํ˜น์€ migrate ํ–ˆ๋Š”๋ฐ๋„ ์ธ์‹์„ ๋ชปํ•ด ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๋ฐ ์ž๋™ ์™„์„ฑ์ด ์•ˆ๋œ๋‹ค๋ฉด, vscode์—์„œ f1์„ ๋ˆ„๋ฅด๊ณ  Restart TS Server ํ•œ๋ฒˆ ๋จน์—ฌ์ฃผ๋ฉด ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ ๋•Œ๋ฌธ์— ๊ฝค๋‚˜ ์‹œ๊ฐ„ ์žก์•„๋จน์—ˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

 

๐Ÿ“Œ Nest CRUD generator

$ nest generate resource post

// ์ถ•์•ฝํ˜•
$ nest g res post

 

ํ•œ๋•€ํ•œ๋•€ ์ง์ ‘ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์ฃผ๊ฑฐ๋‚˜ ์„œ๋น„์Šค, ์ปจํŠธ๋กค๋Ÿฌ, ๋ชจ๋“ˆ ๋“ฑ generate ํ•ด์ฃผ์–ด๋„ ๋˜์ง€๋งŒ NestJS์—๋Š” CRUD generator๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

https://docs.nestjs.com/recipes/crud-generator

 

์œ„ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๊ณ  API ๋ฐฉ์‹์„ ์„ ํƒํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด CRUD์— ํ•„์š”ํ•œ ๋ชจ๋“  ๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค.

 

 

์ƒ์„ฑ๋œ ๋Œ€๋žต์ ์ธ ์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ๋“œ๋ฆฌ๋ฉด ์œ„์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ €๋Š” ์ •๋ง ์ด ๊ธฐ๋Šฅ์„ ์ฒ˜์Œ ๋ง›๋ณธ ํ›„ ์‹ ๋ฌธ๋ฌผ์„ ์ ‘ํ•œ ์›์ฃผ๋ฏผ ๋งˆ๋ƒฅ ๋†€๋ผ ์ž๋น ์กŒ์Šต๋‹ˆ๋‹ค.

 

๊ธฐ๋ณธ์ ์ธ ํด๋” ๊ตฌ์กฐ๋ถ€ํ„ฐ ๊ฐ ํŒŒ์ผ๊ฐ„์˜ ์—ฐ๊ฒฐ, ์ฝ”๋“œ ํ…œํ”Œ๋ฆฟ ์ž‘์„ฑ.

๊ทธ์ € ์ €๋Š” prisma ์—ฐ๊ฒฐ๋งŒ ๋”ธ๊น ํ•ด์ฃผ๋ฉด ๋๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

์ด๋ฅผ ํ†ตํ•ด ์—„์ฒญ๋‚œ ๋น ๋ฅธ ๊ฐœ๋ฐœ์†๋„์™€ ๊ฐœ๋ฐœ์ž ๊ฐ„ ์ฝ”๋“œ ์Šคํƒ€์ผ ํ†ต์ผ ๋“ฑ๋“ฑ ๋‹ค์–‘ํ•œ ์ด์ ์„ ์ฑ™๊ธธ ์ˆ˜ ์žˆ๊ฒ ์ฃ ?

 

๐Ÿ“Œ Service ํŒŒ์ผ ์ž‘์„ฑํ•˜๊ธฐ

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { PrismaService } from 'src/prisma/prisma.service';

@Injectable()
export class UserService {
  constructor(private prisma: PrismaService) {}

  async create(data: CreateUserDto) {
    const user = await this.prisma.user.create({ data });
    return user;
  }

  async findAll() {
    const userList = await this.prisma.user.findMany();
    return userList;
  }

  async findOne(id: number) {
    const user = await this.prisma.user.findUnique({
      where: { id },
    });
    return user;
  }

  async update(id: number, data: UpdateUserDto) {
    const user = await this.prisma.user.update({
      where: { id },
      data,
    });
    return user;
  }

  async remove(id: number) {
    const user = await this.prisma.user.delete({
      where: { id },
    });
    return user;
  }
}

CRUD์— ํ•„์š”ํ•œ 5๊ฐ€์ง€ service๋ฅผ ์ž‘์„ฑํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

prisma๋Š” ๋”ฐ๋กœ ์„ค๋ช…์ด ํ•„์š”์—†์„ ์ •๋„๋กœ ์ง๊ด€์ ์ธ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ”Ž prisma ์„œ๋น„์Šค ์ฃผ์ž… ๋ฐ›๊ธฐ

constructor(private prisma: PrismaService) {}

์ƒ์„ฑ์ž ๋ฐฉ์‹์œผ๋กœ prisma ์„œ๋น„์Šค๋ฅผ ์ฃผ์ž… ๋ฐ›๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

์•„๊นŒ ์œ„์—์„œ prisma module์„ @Global๋กœ ์„ค์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“ˆ์—์„œ ๋ณ„๋„๋กœ import ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿ”Ž ๋Œ€ํ‘œ์ ์ธ prisma CRUD ๋ฉ”์†Œ๋“œ

  • findUnique
    ํŠน์ • ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•  ๋•Œ ์‚ฌ์šฉ
    ex) prisma.user.findUnique({ where: { id: 1 } })
  • findMany
    ์—ฌ๋Ÿฌ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•  ๋•Œ ์‚ฌ์šฉ
    ๋‹ค์–‘ํ•œ ํ•„ํ„ฐ์™€ ์ •๋ ฌ ์˜ต์…˜์ด ๊ฐ€๋Šฅ
  • create
    ์ƒˆ๋กœ์šด ๋ ˆ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€
    ex) prisma.user.create({ data: { name: 'Alice' } })
  • update
    ํŠน์ • ๋ ˆ์ฝ”๋“œ๋ฅผ ์—…๋ฐ์ดํŠธ
    ex) prisma.user.update({ where: { id: 1 }, data: { name: 'Bob' } })
  • delete
    ํŠน์ • ๋ ˆ์ฝ”๋“œ๋ฅผ ์‚ญ์ œ
  • upsert
    ํŠน์ • ์กฐ๊ฑด์— ๋งž๋Š” ๋ ˆ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ณ , ์žˆ์œผ๋ฉด ์—…๋ฐ์ดํŠธ
  • count
    ๋ ˆ์ฝ”๋“œ์˜ ๊ฐœ์ˆ˜๋ฅผ ์…€ ๋•Œ ์‚ฌ์šฉ
  • aggregate
    ์—ฌ๋Ÿฌ ๋ ˆ์ฝ”๋“œ์˜ ํ•„๋“œ๋ฅผ ํ•ฉ์‚ฐ, ํ‰๊ท  ๋“ฑ์„ ๊ตฌํ•  ๋•Œ ์‚ฌ์šฉ
  • groupBy
    ํŠน์ • ํ•„๋“œ๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ ์œ ์šฉ

 

๐Ÿ”Ž prisma transaction

ํŠธ๋žœ์žญ์…˜์€ ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ์–ด, ํ•ด๋‹น ๊ทธ๋ฃน์˜ ์ž‘์—…์ด ๋ชจ๋‘ ์„ฑ๊ณตํ•˜๊ฑฐ๋‚˜ ๋ชจ๋‘ ์‹คํŒจํ•˜๋„๋ก ๋ณด์žฅํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

const create = await prisma.$transaction([
  prisma.user.create({ data: { name: 'Kim' } }),
  prisma.post.create({ data: { title: 'Hello', desc: 'Hi' } }),
]);

$transaction API๋Š” ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ์‚ฐ์„ ๋ฐฐ์—ด๋กœ ๋ฐ›์•„ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์œ„์™€ ๊ฐ™์ด ์—ฌ๋Ÿฌ ์ฟผ๋ฆฌ๋ฅผ ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ, ๋‘ ์ฟผ๋ฆฌ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์‹คํŒจํ•˜๋ฉด ์ „์ฒด ์—ฐ์‚ฐ์ด ๋กค๋ฐฑ๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“Œ NestJS ๋‹ค๋ฅธ ๊ธ€

NestJS ํ”„๋กœ์ ํŠธ ์‹œ์ž‘๊ณผ ๊ตฌ์กฐ์˜ ์ดํ•ด

 

NestJS ํ”„๋กœ์ ํŠธ ์‹œ์ž‘๊ณผ ๊ตฌ์กฐ์˜ ์ดํ•ด

๐Ÿ“’ NestJS ํ”„๋กœ์ ํŠธ ์‹œ์ž‘๊ณผ ๊ตฌ์กฐ์˜ ์ดํ•ด์ง€๊ธˆ์€ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž์ด์ง€๋งŒ ํ•ญ์ƒ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ๋„ ํ•จ๊ป˜ ํ•ด์•ผ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์„ ์ง€๋‹ˆ๊ณ  ์‚ด์•˜์Šต๋‹ˆ๋‹ค.๋‚˜์ค‘์— ์ข‹์€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์œผ๋ฉด ํ˜ผ์ž์„œ ์˜ค๋กฏ์ด ์„ค๊ณ„ํ•˜

lasbe.tistory.com

 

Docker๋กœ PostgreSQL ์„ค์น˜ํ•˜๊ณ  NestJS + prisma ์—ฐ๋™ํ•˜๊ธฐ

 

Docker๋กœ PostgreSQL ์„ค์น˜ํ•˜๊ณ  NestJS + prisma ์—ฐ๋™ํ•˜๊ธฐ

๐Ÿ“’  Docker๋กœ PostgreSQL ์„ค์น˜ํ•˜๊ณ  NestJS + prisma ์—ฐ๋™ํ•˜๊ธฐNestJS๋กœ ๊ฐœ๋ฐœํ•  ๋•Œ ์ฃผ๋กœ prisma์™€ postgresql์„ ์‚ฌ์šฉํ•˜๋Š” ์ถ”์„ธ์ž…๋‹ˆ๋‹ค.์™œ ์–ด๋– ํ•œ ํŠน์žฅ์ ์ด ์žˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์ดˆ๊ธฐ ์„ค์น˜ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ

lasbe.tistory.com

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€


์˜คํ”ˆ ์ฑ„ํŒ