아주 아주 간단한 영화 리뷰 api를 만들어보기로 한다.
ER diagram은 위와 같다. 사용자의 정보를 저장하는 user와 영화의 정보를 저장하는 movie, 영화 리뷰를 저장하는 record, 총 세 개의 table이 존재한다.
tsconfig.json
"esModuleInterop": true,
추가
바로
import { } from ''
를 쓸 수 있게 해준다.
$ npm add @nestjs/typeorm typeorm mysql @nestjs/graphql apollo-server-express
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
""
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 {}
typeorm에서는 entity
를 통해 모델을 정의하고, graphql에서는 typeDefs
를 통해 데이터 타입(그리고 요청의 타입) 을 정의한다.
TypeORM과 graphql의 모델을 한 번에 정의하기 위해 graphql의 code first를 이용한다.
- code first
GraphQL schema를 만들기 위해 decorator와 class를 이용하는 방법이다. GraphQLModule의
autoSchemaFile
을 true로 해줬던 이유.
@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...)가 될 수 있다.
nullable
, description
(설명)
@Field(() => Boolean, { defaultValue: true })
@Column({ default: true })
이런식으로 이용 가능하다
https://github.com/typeorm/typeorm/blob/master/docs/listeners-and-subscribers.md
@BeforeInsert()
: Entity가 db에 save되기 전에 실행될 함수를 지정할 수 있다.
@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
모델 추가해주기
entity manager
를 이용하여 entity를 삽입, 갱신하는 등의 관리를 할 수 있다. repository는 entity manager과 유사하지만 entity manager가 모든 entity에 대한 권한을 갖는 반면, repository는 특정 entity에 대한 관리 권한만을 갖는다.
repository를 사용하기 위해서는 module에 등록을 먼저 해야한다.
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를 사용 가능하다.
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해주어야 한다.
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 를 이용하여 넣어줄 수 있다.
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 {}
@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