nestjs + graphql + typeorm 시작하기, entity 만들기

김가영·2021년 4월 11일
3

Node.js

목록 보기
28/34

아주 아주 간단한 영화 리뷰 api를 만들어보기로 한다.

ER diagram은 위와 같다. 사용자의 정보를 저장하는 user와 영화의 정보를 저장하는 movie, 영화 리뷰를 저장하는 record, 총 세 개의 table이 존재한다.

Setting

tsconfig.json

"esModuleInterop": true, 추가

바로 import { } from '' 를 쓸 수 있게 해준다.

  • Terminal

$ npm add @nestjs/typeorm typeorm mysql @nestjs/graphql apollo-server-express

database 연결하기

  • app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'admin',
      port: 3306,
      username: process.env.MYSQL_USERNAME,
      password: process.env.MYSQL_PASSWORD,
      database: 'typeorm',
      entities: [],
      synchronize: true,
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

또는 ormconfig.json을 따로 만들수도 있다.


그럴땐 app.module.ts를 다음과 같이 구성해준다.

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot(),
    GraphQLModule.forRoot({
      autoSchemaFile: 'schema.gql',
    }),
    UserModule,
    MovieModule,
    RecordModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

.env 환경 변수 이용하기

npm i --save @nestjs/config

  • .env 파일을 생성하여 변수를 넣어준다. ("" or ''를 쓰지 않고 바로 변수를 넣어준다. Ex: name = admin) 이떄 TypeOrmModule에서 환경변수를 사용하므로 ConfigModule은 TypeOrmModule 앞에 import해주어야 한다.
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'db-sopt-server.ctgkac4hty0u.ap-northeast-2.rds.amazonaws.com',
      port: 3306,
      username: process.env.MYSQL_USERNAME,
      password: process.env.MYSQL_PASSWORD,
      database: 'typeorm',
      entities: [],
      synchronize: true,
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Entity 만들기

typeorm에서는 entity를 통해 모델을 정의하고, graphql에서는 typeDefs를 통해 데이터 타입(그리고 요청의 타입) 을 정의한다.

TypeORM과 graphql의 모델을 한 번에 정의하기 위해 graphql의 code first를 이용한다.

  • code first

GraphQL schema를 만들기 위해 decorator와 class를 이용하는 방법이다. GraphQLModule의 autoSchemaFile을 true로 해줬던 이유.

  • users/user.entity/ts

@ObjectType, @Field 는 graphql의 decorator,

@Column, @Entity는 typeorm의 decorator이다.

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { Field, Int, ObjectType } from '@nestjs/graphql';

@ObjectType()
@Entity()
export class User {
  @Field(() => Int)
  @PrimaryGeneratedColumn()
  id: number;

  @Field(() => String, { nullable: true })
  @Column()
  nickname?: string;

  @Field(() => String)
  @Column()
  password: string;

  @Field(() => Boolean, { defaultValue: true })
  @Column({ default: true })
  flag_active: boolean;
}

field에 들어가는 것은 다른 Object나 scalar(ID, String, Boolean, Int...)가 될 수 있다.

Options

nullable, description(설명)

@Field(() => Boolean, { defaultValue: true })
  @Column({ default: true })

이런식으로 이용 가능하다

Listeners and Subscribers

https://github.com/typeorm/typeorm/blob/master/docs/listeners-and-subscribers.md

@BeforeInsert() : Entity가 db에 save되기 전에 실행될 함수를 지정할 수 있다.

  • app.module.ts
@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'db-sopt-server.ctgkac4hty0u.ap-northeast-2.rds.amazonaws.com',
      port: 3306,
      username: process.env.MYSQL_USERNAME,
      password: process.env.MYSQL_PASSWORD,
      database: 'typeorm',
      entities: [User],
      synchronize: true,
    }),
...

entities 에 User 모델 추가해주기

Repository 사용하기 (entity 관리하기)

entity manager 를 이용하여 entity를 삽입, 갱신하는 등의 관리를 할 수 있다. repository는 entity manager과 유사하지만 entity manager가 모든 entity에 대한 권한을 갖는 반면, repository는 특정 entity에 대한 관리 권한만을 갖는다.

repository를 사용하기 위해서는 module에 등록을 먼저 해야한다.

  • users/users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { User } from './user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

forFeature() : 어떤 repositories가 사용될 지를 알려준다.

forFeature()를 모듈에 등록해뒀으면 해당 Service provider에서 InjectRepository를 통해 repository를 사용 가능하다.

  • users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}

  findById(id: number): Promise<User> {
    return this.userRepository.findOne(id);
  }
}

다른 module에서 해당 repository를 사용하기 위해서는 전체 module을 export해주어야 한다.

  • users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { User } from './user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  exports: [TypeOrmModule],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

다른 모듈에서도 module을 통째로 import한 후 역시 @InjectRepository 를 이용하여 넣어줄 수 있다.

  • movies.module.ts
import { Module } from '@nestjs/common';
import { MoviesService } from './movies.service';
import { MoviesController } from './movies.controller';
import { UsersController } from 'src/users/users.controller';
import { UsersModule } from '../users/users.module';
import { UsersService } from '../users/users.service';

@Module({
  imports: [UsersModule],
  providers: [MoviesService, UsersService],
  controllers: [MoviesController, UsersController],
})
export class MoviesModule {}
  • records.service.ts
@Injectable()
export class RecordsService {
  constructor(
    @InjectRepository(Record)
    private recordRepository: Repository<Record>,
    @InjectRepository(User)
    private userRepository: Repository<User>,
    @InjectRepository(Movie)
    private movieRepository: Repository<Movie>,
  ) {}
...
}

다른 entity + 자세한 내용은 github - https://github.com/jujube0/nest-graphql-typeorm

profile
개발블로그

0개의 댓글