๐ NestJS๋ก ํธ๋ฆฌํ๊ฒ CRUD ๊ตฌํํ๊ธฐ
์์ฆ NestJS๋ฅผ ์กฐ๊ธ์ฉ ๊ณต๋ถํ๋ฉฐ ์ง๋๋ฅผ ๋๊ฐ๊ณ ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ์ฌ์ฉํ๋ฉด ์ฌ์ฉํ ์๋ก "์ ๋ง ํธ๋ฆฌํ๋ค"๊ณ ๋๋ผ๋ ์ค์ ๋๋ค.
๊ทธ๋ผ NestJS์ prisma๋ก CRUD api๋ฅผ ๊ตฌ์ฑํ๋ ๊ณผ์ ์ ์๊ฐ๋๋ฆฌ๋ฉด์ ์ด๋ ํ ์ ์ด ํธ๋ฆฌํ๋์ง ์ค๋ช ํ๊ฒ ์ต๋๋ค.
๐ prisma ์ค์น ๊ณผ์
prisma๋ฅผ ์ค์นํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฐ๋ํ๋ ๊ณผ์ ์ ๋ค์ ๊ธ์ ์์ธํ ์๊ฐ๋์ด์์ต๋๋ค.
๐ 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 ํ๋ก์ ํธ ์์๊ณผ ๊ตฌ์กฐ์ ์ดํด
Docker๋ก PostgreSQL ์ค์นํ๊ณ NestJS + prisma ์ฐ๋ํ๊ธฐ
'NestJS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Docker๋ก PostgreSQL ์ค์นํ๊ณ NestJS + prisma ์ฐ๋ํ๊ธฐ (0) | 2024.10.31 |
---|---|
NestJS ํ๋ก์ ํธ ์์๊ณผ ๊ตฌ์กฐ์ ์ดํด (0) | 2024.10.28 |
๋๊ธ