728x90

1. Prisma의 의미

Prisma는 차세대 Node.js, TypeScript ORM 기술로서, 미리 정의한 모델인 GraphQL 스키마를 기반으로 DB의 필드, 속성을 자동생성(CREATE TABLE) 해준다. 이해하기 쉬운 데이터 모델 작성, migration 자동화 기능, type safe 및 auto-completion 기능 덕분에 데이터베이스 작업 시 편리하다.

 

1.1. GraphQL의 의미와 장점

facebook에서 만든 Graph Query Language 로 어플리케이션 쿼리 언어로써, 기존의 REST API의 한계점을 극복하고자 나온 통신 규약이다.

 

Node.js를 이용해, 데이터베이스에 접근하는 나만의 명령어를 만들고 (Query, Mutation, TypeDefs, resolvers ) CRUD 요청, 응답을 더 효과적으로 처리할 수 있게 해주는 API 이다.

 

REST API의 다음과 같은 문제를 해결한다.

- 원하는 데이터보다 쓸데없이 더많은 데이터를 가져오는 문제(over-fetching)
- 특정 데이터를 요청하기위해 여러 번의 요청을 해야하는 문제(under-fetching)

 

1.2. ORM (Object Relational Mapping)의 의미와 장단점

Application단에서 모델을 생성하기만 하면, DBMS(관계형 데이터베이스)에서 CREATE TABLE할 필요 없이 모델의 필드와 속성에 맞춰 데이터베이스가 생성되어 매핑되는 것을 말한다. 

 

장점

- Application단의 모델과 DBMS의 테이블간의 필드, 속성 불일치 문제를 해결한다.

- 모델에 기반한 코드를 작성하므로 직관적이다.

- 관계형 데이터베이스의 테이블 생성, 필드 설정 같은 작업이 생략되므로,  Backend 개발자는 비즈니스 로직에 집중할 수 있다.

- Backend 내에서 데이터를 가져오는 코드를 작성하므로 재사용성, 가독성, 유지보수성, 생산성이 증가한다.

- 객체-테이블 매핑정보가 명확하여, ERD를 보는 것에 대한 의존도를 낮출 수 있다.

- 객체 간의 관계를 바탕으로 SQL을 자동으로 생성하기 때문에 오류 발생률이 적다.

- DBMS를 교체하는 거대한 작업에도 migration 기능을 통해 비교적 적은 리스크와 시간이 소요된다.

 

단점
- 사용하기는 편하지만 설계는 매우 신중하게 해야한다.
- 프로젝트의 복잡성이 커질경우 난이도 또한 올라갈 수 있다.
- 잘못 구현된 경우에 속도 저하 및 심각할 경우 일관성이 무너지는 문제점이 생길 수 있다.
- 일부 자주 사용되는 대형 쿼리는 속도를 위해 SP를 쓰는등 별도의 튜닝이 필요한 경우가 있다.
- DBMS의 고유 기능을 이용하기 어렵지만 특정 DBMS의 고유기능을 이용하면 이식성이 저하되기 때문에 피하자.
- 프로시저가 많은 시스템에선 ORM의 객체 지향적인 장점을 활용하기 어렵다

 

2. Prisma 사용법

2.1. migration 파일

DB 스키마를 정의

// 가장 최근의 migration 파일을 사용
// migration 파일이 없으면 새로 만듬
npx prisma migrate dev

 

generator client {
  provider = "prisma-client-js"
}

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

// 유저 정보 테이블
model User {
  id    Int     @default(autoincrement()) @id
  emailLogin String  @unique
  emailAuth String  @unique
  password String
  name String
  nickname String
  schoolYear String
  schoolType String
  sex String
  region String
  schoolName String
  regDate DateTime @default(now())
  updateDate DateTime @default(now()) @updatedAt
  userEventScore UserEventScore[]
  userTotalScore UserTotalScore[]
  userFactorEvent UserFactorEvent[]
  board Board[]
}

// 유저 종목별 점수
model UserEventScore {
  id    Int     @default(autoincrement()) @id
  user  User  @relation(fields: [userId], references: [id])
  userId  Int
  factor  String
  event String
  measure String
  score Int
  grade String
  percentile  Float
  regDate DateTime @default(now())
  updateDate  DateTime @default(now()) @updatedAt
}

 

데이터베이스 수업을 들었거나, 데이터베이스를 설계해 본 사람이라면, 위 코드 대부분이 이해가 갈 것이다.

 

특이한 점은 FK(Foreign key)를 설정하는 방법인데,

userEventScore UserEventScore[]

user  User  @relation(fields: [userId], references: [id])

userId  Int

이 부분인데, FK(Foreign key)를 설정할 때 기본키를 가지고 있는 UserEventScore 테이블에서는 userId와 User  @relation를 추가해준다. FK 관계 테이블인 User에는 userEventScore UserEventScore[]를 추가해준다.

 

 

2.2. Request Model 정의

export interface UserRequest {
  emailLogin: string;
  emailAuth: string;
  password: string;
  name: string;
  nickname: string;
  schoolYear: string;
  schoolType: string;
  sex: string;
  region: string;
  schoolName: string;
}

 

2.3. Service 비즈니스 로직 작성

public async createUser(user: UserRequest): Promise<TokenResponse> {
  try {
    const res = await prisma.user.create({
      data: user,
    });
    const token: string = await this.generateAccessToken(res.id);
    return {
      id: res.id,
      token: token,
    };
  } catch (e) {
    throw e;
  }
}

회원가입을 하면 데이터베이스가 입력한 회원정보가 등록되는 코드가 3줄로 작성된다. 

 

2.3. route 코드 작성

route.post('/user', async (req: Request, res: Response) => {
  try {
    const userRequest: UserRequest = req.body;
    const tokenResponse: TokenResponse = await userService.createUser(userRequest);
    res.status(200).json({
      code: 200,
      msg: '',
      data: tokenResponse,
    });
  } catch (e) {
    if (e instanceof Error) {
      res.status(500).send({ message: e.message });
    } else {
      res.status(500).send({ message: 'Undefined Error!' });
    }
  }
});

 

prisma가 생성한 데이터베이스에 데이터가 잘 들어간 것을 확인할 수 있다.

 

Next Todo

회원가입 시 password 암호화하기 (단방향 암호화를 사용하여 복호화 불가능하게 함)

https://velog.io/@jiheon/Node.js-crypto%EB%A1%9C-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EC%95%94%ED%98%B8%ED%99%94%ED%95%98%EA%B8%B0

 

 

 

+ Recent posts