이번 시간에는 Node.js & TypeScript의 ORM 중 하나인 Prisma에 대해 알아봅시다.

공부할 내용 📚

1. Prisma가 무엇인가요?

ORM…?? ORM은 뭐고, Prisma는 또 무엇일까요?

ORM의 의미와, Prisma가 어떤 서비스인지 한 번 알아봅시다!

  • ORM이 뭘까?: ORM이 뭔지 간단히 알아봅시다!
    • 이외에도 구글링하면 ORM에 대해서 많은 정보들이 나오니 참고해주세요! 😀
  • Is Prisma an ORM?: Prisma 공식문서에서 Prisma가 무엇인지, 어떤 원리로 작동되는지에 대해서 간단히 소개해줍니다.
    • Prisma란?: 한글로도 짧게 정리한 블로그 글도 가져와봤습니다!

2. Prisma

이제 ORM이 무엇이고, Prisma는 어떤 서비스인지 알아보았으니 구체적으로 어떻게 사용할 수 있는지 알아볼까요?

  • What is Prisma?: Prisma의 작동 원리에 대해서 알아봅니다. 꼭 읽어봐주세요!! ⭐️
  • Prisma schema: Prisma는 schema 파일을 통해 다양한 설정 정보를 얻고 어떠한 데이터 모델을 생성할지 파악합니다. schema 파일이 어떻게 구성되어 있고, 데이터 모델은 어떻게 작성할 수 있는지 살펴봐야겠죠? 😆
  • Prisma CRUD: Prisma에서는 아주 많은…. 기능들이 있는데요, 이번에는 그중 실습때 쓰이는 CRUD관련 기능만 살펴봐주세요 🙂
  • Prisma Playground: Prisma에서는 Playground를 통해 웹에서도 테스트할 수 있도록 해줘요! Playground를 통해 한 번 테스트해봐도 좋아요!

프로젝트 실습 🎈

이번 주차는 저번 주차에서 만들었던 Nest.js 웹서버에서 실제 데이터베이스(PostgreSQL)에 prisma를 이용하여 CRUD 코드를 작성해보는 과제입니다.

환경 설정 관련해서 아래 지시사항을 따라해주세요! 물론 꼭 그대로 따라하실 필요는 없고 자신의 데이터 구조에 따라 바꾸셔도 괜찮습니다!

실습 세부 설명 ⚙️

환경세팅과 관련해서 도와드릴게요! 밑의 절차를 따라와주세요

참고 : https://www.prisma.io/blog/nestjs-prisma-rest-api-7D056s1BmOL0

시작 전, Docker 설치 가이드를 참고하여 Docker를 설치해주세요!

Root 디렉토리에 docker-compose.yml를 생성하고, 아래 파일을 복사-붙여넣기 해주세요.

# docker-compose.yml

version: '3.8'
services:
  postgres:
    image: postgres:13.5
    restart: always
    environment:
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mypassword
    volumes:
      - postgres:/var/lib/postgresql/data
    ports:
      - '5432:5432'

volumes:
  postgres:

그 뒤, 터미널에서 docker-compose up -d 을 실행하고(-d는 백그라운드에서 실행하는 옵션) , 정상적으로 컨테이너가 생성되고 실행되는지 확인해주세요

  • 터미널에 Running 표시 혹은 docker gui 에서 실행되고 있다면 성공입니다
  • 🛠️ 백그라운드에서 정상적으로 작동해야지 밑의 과정에서 오류가 생기지 않습니다!

다음으로 터미널에 npm install -D prisma 을 입력해 prisma 를 설치해줍니다.

루트 디렉토리에서 npx prisma init 를 입력하면, prisma 폴더와 Schema 파일이 생성된 것을 확인할 수 있습니다.

  • 루트 폴더에 .env 파일이 생성되었는 것을 볼 수 있는데요, 안에는 database_url 이 들어있을 건데 밑과 같이 변경해줍니다.

    // .env
    DATABASE_URL="postgres://myuser:mypassword@localhost:5432/median-db"

prisma/schema.prisma 에 들어가 맨 밑에 restaurant model 을 추가해줍시다!

  • 자신의 데이터구조에 맞게 자유롭게 작성해주시면 됩니다! 제가 작성한 예시를 남겨드립니다.

    // This is your Prisma schema file,
    // learn more about it in the docs: https://pris.ly/d/prisma-schema
    
    generator client {
    provider = "prisma-client-js"
    }
    
    datasource db {
    provider = "postgresql"
    url      = env("DATABASE_URL")
    }
    
    model Restaurant {
    id          Int      @id @default(autoincrement())
    name       String   @unique
    address String
    phone        String
    createdAt   DateTime @default(now())
    updatedAt   DateTime @updatedAt
    }

다음, 우리가 생성한 데이터 모델을 migrate하기 위해 아래 명령어를 입력해줍니다.

npx prisma migrate dev --name "init"
  • 성공적으로 되었다면 terminal에 Your database is now in sync with your schema라는 문장과 함께 prisma 안에 migration 폴더가 생성되는 것을 확인할 수 있어용

원활한 테스팅을 위해 데이터베이스에 미리 seed 데이터도 심어놓읍시다.

  • 아래 seed.ts를 생성해주세요! (데이터 구조는 자신의 것과 일치하게 수정해주셔도 됩니당)
// prisma/seed.ts

import { PrismaClient } from '@prisma/client';

// initialize Prisma Client
const prisma = new PrismaClient();

async function main() {
  // create two dummy articles
  const restaurant1 = await prisma.restaurant.upsert({
    where: { name: '봉수육' },
    update: {},
    create: {
      name: '봉수육',
      address: '경기 수원시 장안구 율전로108번길 11 1층',
      phone: '0507-1460-0903',
    },
  });

  const restaurant2 = await prisma.restaurant.upsert({
    where: { name: '청년밥상' },
    update: {},
    create: {
      name: '청년밥상',
      address: '경기 수원시 장안구 서부로2136번길 10 1층',
      phone: '0507-1307-1822',
    },
  });

  console.log({ restaurant1, restaurant2 });
}

// execute the main function
main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    // close Prisma Client at the end
    await prisma.$disconnect();
  });

그리고 package.json에 아래 명령어를 추가해주세요.

// package.json

// ...
  "scripts": {
    // ...
  },
  "dependencies": {
    // ...
  },
  "devDependencies": {
    // ...
  },
  "jest": {
    // ...
  },
  **"prisma": {
    "seed": "ts-node prisma/seed.ts"
  }**

그리고 터미널에 npx prisma db seed를 입력해주시면 귀여운 새싹모양 아이콘이 뜰거에요ㅎ.ㅎ

prisma를 연결해주기 위해

npx nest generate module prisma
npx nest generate service prisma

를 입력해주시고, prisma.service.ts 파일을 조금 수정해줍니다.

// src/prisma/prisma.service.ts

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

@Injectable()
export class PrismaService extends PrismaClient {
  async enableShutdownHooks(app: INestApplication) {
    this.$on('beforeExit', async () => {
      await app.close();
    });
  }
}

그리고 prisma.module.ts 도 수정해줍니다. (exports에 추가)

// src/prisma/prisma.module.ts

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

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

마지막으로 저희 Restaurant 모듈에서 쓰기 위하여 service, module 파일을 조금 수정해주세요!

  • 밑에는 예시 코드입니다.
//restaurant.module.ts
import { Module } from '@nestjs/common';
import { PrismaModule } from 'src/prisma/prisma.module';
import { RestaurantController } from './restaurant.controller';
import { RestaurantService } from './restaurant.service';

@Module({
  controllers: [RestaurantController],
  providers: [RestaurantService],
  imports: [PrismaModule],
})
export class RestaurantModule {}
//restaurant.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';

@Injectable()
export class RestaurantService {
  constructor(private prisma: PrismaService) {}
	
	//example
  async getAllRestaurants() {
    return await this.prisma.restaurant.findMany({
      select: {
        name: true,
        address: true,
        phone: true,
      },
    });
  }
}

이제 직접 CRUD 코드를 작성하면 됩니다. 😆

  • 참고로, npx prisma studio 를 입력하면 5555포트에서 정말 간편하게 db 를 눈으로 확인할 수 있으니 애용해주세요 😻