블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2021. 9. 24. 19:48 React/Architecture

MS-4/5/6 글을 통해 Gateway의 공통 기능 구현을 위한 설정을 적용한다.

  • Login 할때 사용자 정보는 ORM 기반으로 처리한다.
  • 인증을 JWT 기반으로 처리한다.
  • Login 화면을 React 기반 구현한다.

 

NestJS에 Prisma ORM 설정

gateway-api의 공통 기능은 다음과 같고, JWT처리를 위한 사용자 정보 조회를 위해 Prisma ORM을 적용한다. Micro Service도 Prisma를 사용할 것이다.

  • api gateway: TCP 통신으로 micro service의 API를 연결한다. 
  • http server: gateway의 공통 기능중 Login을 서비스한다.
  • reverse proxy: Login이 성공하면 dashboard micro service로 이동한다. (configuration, back-office)
  • auth server: JWT 기반으로 token을 발행하고, 요청에 대한 모든 Authorization(인가, 권한)을 체크한다.

 

Step-1) 설치 및 환경 설정

auth server 기능에서 사용자 정보 데이터처리를 위해 ORM으로 Prisma를 사용을 위해 패키지를 (v3.1.1) 설치한다.

$> yarn add -D prisma
$> yarn add @prisma/client
$> yarn add -D ts-node

전체 애플리케이션을 위한 초기 prisma 환경을 생성한다.

$> npx prisma init

✔ Your Prisma schema was created at prisma/schema.prisma
  You can now open it in your favorite editor.

Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver (Preview) or mongodb (Preview).
3. Run prisma db pull to turn your database schema into a Prisma schema.
4. Run prisma generate to generate the Prisma Client. You can then start querying your database.

More information in our documentation:
https://pris.ly/d/getting-started

자동 생성된 .env 파일에 설정을 추가한다. 

# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server (Preview) and MongoDB (Preview).
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
#DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"

# POSTGRES
POSTGRES_USER=iot
POSTGRES_PASSWORD=1
POSTGRES_DB=rnm-stack

# Nest run locally
DB_HOST=localhost
# Nest run in docker, change host to database container name
# DB_HOST=postgres
DB_PORT=5432
DB_SCHEMA=public

# Prisma database connection
DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${DB_HOST}:${DB_PORT}/${POSTGRES_DB}?schema=${DB_SCHEMA}&sslmode=prefer

VS Code의 extension을 설치한다. 

VSCode의 prisma extension

 

Step-2) schema.prisma 설정

VSCode extension이 설치되면 schema.prisma의 내용이 다음과 같이 highlighting된다. 

schema.prisma 파일 안에 Prisma 방식의 스키마를 정의한다.

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

generator client {
  provider = "prisma-client-js"
  // previewFeatures = []
}

// generator dbml {
//   provider = "prisma-dbml-generator"
// }

model User {
  id        Int   @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  email     String   @unique
  password  String
  firstname String?
  lastname  String?
  posts     Post[]
  role      Role
}

model Post {
  id        Int   @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  published Boolean
  title     String
  content   String?
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}

enum Role {
  ADMIN
  MANAGER
  USER
}

schema.prisma를 통해 Migrate SQL과 Prisma Client 파일을 자동 생성한다. Prisma Client 파일은 구현 코드에서 사용된다. (참조)

 

 

Step-3) schema 설정을 통해 sql 생성하기 

명령을 수행하면 prisma/migrations sql이 자동 실행된다. 생성된 sql을 통해 table schema를 업데이트한다. 변경점이 있으면 날짜별로 update 할 수 있는 table schema가 자동으로 생성된다. 

$> npx prisma migrate dev --create-only --name=iot

또한 DB Schema에 _prisma_migrations 테이블이 자동생성된다. 

rnm-stack 의 public에 migrations 테이블 자동 생성

테이블을 자동 생성하고 싶다. prisma db push 명령을 사용한다. (참조)

$> npx prisma db push

Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "rnm-stack", schema "public" at "localhost:5432"
🚀  Your database is now in sync with your schema. Done in 77ms
✔ Generated Prisma Client (3.1.1) to ./node_modules/@prisma/client in 61ms

Post, User 테이블 자동 생성

 

Step-4) Prisma Studio 사용하기

prisma는 내장 웹기반 studio를 제공한다. 테이블을 선택하여 조작할 수 있다.

$> npx prisma studio

 

 

NestJS 에서 PrismaClient  사용하기

Step-1) PrismaClient 생성

schema에 생성되었으면 다음으로 코드에서 Prisma 접근을 위해 PrismaClient를 생성해야 한다. (참조)

  • "npx prisma migrate dev" 명령으로 수행할 경우는 "npx prisma generate"이 필요없다. 
  • "npx prisma migrate dev --create-only" 일 경우만 수행한다.
  • schema.prisma 변경시 마다 다시 실행해 주어야 한다. (참조)

$> npx prisma generate
✔ Generated Prisma Client (3.1.1) to ./node_modules/@prisma/client in 181ms
You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client
```
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
```

prisma client는 기본적으로 node_modules/.prisma/client 폴더 밑에 생성된다.

node_modules/.prisma/client 폴더

 

 

Step-2) schema.prisma가 변경이 발생할 경우

이제 "PrismaClient"를 import해서 사용할 수 있는 상태가 되었다. 만일 테이블 변경이 발생한다면 아래와 같이 수행한다. 

  • schema.prisma 파일 내역 수정
  • "npx prisma migrate" 명령 실행
  • migrations 폴더에 있는 migration sql을 database에 적용한다. 

참조: https://www.prisma.io/blog/prisma-migrate-ga-b5eno5g08d0b

 

 

Step-3) NestJS 서비스 생성

사용자 정보는 공통이므로 libs/domain 에 생성한다. (참조)

  • libs/shared/src/lib밑으로 prisma 폴더를 생성하고, prisma-client.service.ts파일을 생성한다. 
  • index.ts에 export를 추가한다. 

// prisma-client.service.ts 
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common'
import { PrismaClient } from '@prisma/client'

@Injectable()
export class PrismaClientService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
  async onModuleInit() {
    await this.$connect()
  }

  async onModuleDestroy() {
    await this.$disconnect()
  }
}

// index.ts
export * from './lib/configuration/config.model';
export * from './lib/configuration/config.service';
export * from './lib/prisma/prisma-client.service';

apps/gateway/api/src/app/app.module.ts에 PrismaClientService를 추가한다.

// /apps/gateway/api/src/app/app.module.ts
import { Module } from '@nestjs/common';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

import { GatewayApiAppService } from '@rnm/domain';
import { PrismaClientService } from '@rnm/shared'; <== 요기

import { AppController } from './app.controller';
import { DashboardModule } from './dashboard/dashboard.module';

@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, 'public'),
      exclude: [
        '/api/gateway*', '/api/dashboard*',
        '/dashboard*', '/configuration*', '/back-office*'
      ],
    }),
    DashboardModule
  ],
  controllers: [AppController],
  providers: [GatewayApiAppService, PrismaClientService] <== 요기
})
export class AppModule { }

gateway/api/src/app/app.controller.ts에 테스트 코드로 POST로 user를 생성하는 코드를 작성한다. 

// apps/gateway/api/src/app/app.controller.ts
import { Body, Controller, Get, Post } from '@nestjs/common';

import { GatewayApiAppService } from '@rnm/domain';
import { PrismaClientService } from '@rnm/shared';

import { Role, User as UserModel } from '@prisma/client';

@Controller('api/gateway')
export class AppController {
  constructor(
    private readonly appService: GatewayApiAppService,
    private readonly dbService: PrismaClientService
  ) { }

  @Get()
  getData() {
    return this.appService.getData();
  }

  @Post('user')
  async createUser(@Body() userData: {
    email: string,
    password: string,
    firstname: string,
    lastname; string,
    role: Role
  }): Promise<UserModel> {
    const { email, password, firstname, lastname, role } = userData;
    return this.dbService.user.create({
      data: {
        email,
        password,
        firstname,
        lastname,
        role: !role ? Role.USER : role
      }
    });
  }
}

VSCode에서 Debug창에서 Gateway를 실행하고, 디버깅을 한다.

28, 29줄에 breakpoint 

 

Postman을 실행하여 User 를 생성해 본다.

  • 새로운 Request를 만들고 POST를 선택
  • Body에 JSON 타입을 선택
  • request 값을 넣고, http://localhost:8000/api/gateway/user 호출

DB툴로 User insert가 되었는지 확인 또는 prisma studio에서 확인

test@test.com 사용자가 insert 성공!

 

소스: https://github.com/ysyun/rnm-stack/releases/tag/ms-4

 

<참조>

- Primsa on NestJS 기반 개발

https://www.prisma.io/nestjs

 

NestJS Database & Prisma | Type-safe ORM for SQL Databases

Prisma is a next-generation ORM for Node.js & TypeScript. It's the easiest way to build NestJS apps with MySQL, PostgreSQL & SQL Server databases.

www.prisma.io

- Prisma Migrate 순서

https://www.prisma.io/blog/prisma-migrate-ga-b5eno5g08d0b

 

Prisma Migrate is Production Ready - Hassle-Free Database Migrations

Prisma Migrate is ready for use in production - Database schema migration tool with declarative data modeling and auto-generated, customizable SQL migrations

www.prisma.io

- Primsa, JWT on NestJS StartKit

https://github.com/fivethree-team/nestjs-prisma-starter

 

GitHub - fivethree-team/nestjs-prisma-starter: Starter template for NestJS 😻 includes GraphQL with Prisma Client, Passport-JW

Starter template for NestJS 😻 includes GraphQL with Prisma Client, Passport-JWT authentication, Swagger Api and Docker - GitHub - fivethree-team/nestjs-prisma-starter: Starter template for NestJS 😻...

github.com

- Prisma의 다양한 DB 예제

https://github.com/prisma/prisma-examples

 

GitHub - prisma/prisma-examples: 🚀 Ready-to-run Prisma example projects

🚀 Ready-to-run Prisma example projects. Contribute to prisma/prisma-examples development by creating an account on GitHub.

github.com

posted by 윤영식