Home NestJS 프로젝트 시작하기 with docker(2)
Post
Cancel

NestJS 프로젝트 시작하기 with docker(2)

이번 포스트에서는 controller와 service를 생성하고 NestJS와 mysql을 연결하는 방법을 알아본다.

nest js cli

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌───────────────┬─────────────┬──────────────────────────────────────────────┐
│ name          │ alias       │ description                                  │
│ application   │ application │ Generate a new application workspace         │
│ class         │ cl          │ Generate a new class                         │
│ configuration │ config      │ Generate a CLI configuration file            │
│ controller    │ co          │ Generate a controller declaration            │
│ decorator     │ d           │ Generate a custom decorator                  │
│ filter        │ f           │ Generate a filter declaration                │
│ gateway       │ ga          │ Generate a gateway declaration               │
│ guard         │ gu          │ Generate a guard declaration                 │
│ interceptor   │ in          │ Generate an interceptor declaration          │
│ interface     │ interface   │ Generate an interface                        │
│ middleware    │ mi          │ Generate a middleware declaration            │
│ module        │ mo          │ Generate a module declaration                │
│ pipe          │ pi          │ Generate a pipe declaration                  │
│ provider      │ pr          │ Generate a provider declaration              │
│ resolver      │ r           │ Generate a GraphQL resolver declaration      │
│ service       │ s           │ Generate a service declaration               │
│ library       │ lib         │ Generate a new library within a monorepo     │
│ sub-app       │ app         │ Generate a new application within a monorepo │
│ resource      │ res         │ Generate a new CRUD resource                 │
└───────────────┴─────────────┴──────────────────────────────────────────────┘

터미널에 nest를 치면 나오는 설명이다.

Module

1
2
nest generate module users
nest g mo users

users의 모듈을 위 명령으로 생성한다.

Controller

1
2
nest generate controller users
nest g co users

controller를 명령어로 생성할 수 있다. 위 명령어를 사용하게 되면 users.controller.ts파일과 users.controller.spec.ts 파일이 생성된다. spec파일은 여기서 설명하지 않는다.

Service

1
2
nest generate service users
nest g s users

위 명령어를 사용하게 되면 users service를 생성 할 수 있다. service 또한 spec 파일이 생성된다.

mysql 연결하기

데이터베이스는 mysql을 사용하고 데이터베이스를 조작하는 도구는 typeorm 을 사용한다.

1
yarn add mysql2 typeorm @nestjs/typeorm

User 테이블 정의하기

사용자 테이블을 간단하게 구성하고 테스트 할 것이다. user를 정의해 보자. users 폴더 안에 entities 폴더를 만들고 user.entity.ts를 생성한다.

user.entity.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { Exclude } from "class-transformer";
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class Users {
  @PrimaryGeneratedColumn("increment")
  id: number;

  @Column()
  user_id: string;

  @Column()
  name: string;

  @Column()
  email: string;

  @Column()
  password: string;
}

user 테이블을 정의한다. User class 위에 @Entity 데코레이터를 추가해서 테이블임을 명시한다. typeorm의 데코레이터로 테이블의 속성을 정의한다.

database module

1
nest g mo database

위 명령어로 database module을 생성한다. database 폴더에 database.provider.ts를 생성한다.

config

default.yml

1
2
3
4
5
6
7
8
9
10
server:
  port: 5001

db:
  type: "mysql"
  port: 3306
  database: "schema name"

jwt:
  expiresIn: 3600

development.yml

1
2
3
4
5
6
7
8
db:
  host: "34.64.45.109"
  username: "root"
  password: "pw"
  synchronize: true

jwt:
  secret: "mysecret123key"

production.yml

1
2
db:
  synchronize: false

src/config 폴더 안에 3개의 yml 파일을 정의한다. development와 production 환경에 대한 실행은 이후에 추가할 예정이다.

typeormconfig.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import * as config from "config";

const dbConfig = config.get("db"); // db config

export const typeormGCP: DataSourceOptions = {
  type: dbConfig["type"],
  host: dbConfig["host"],
  port: dbConfig["port"],
  username: dbConfig["username"],
  password: dbConfig["password"],
  database: dbConfig["database"],
  entities: ["dist/**/*.entity{.ts,.js}"],
  synchronize: true,
};

typeorm을 사용해 데이터베이스를 정의하게 되며, dotenv 대신 config를 사용했다. config 환경 설정은 yml파일로 정의한다.

database.provider.ts

1
2
3
4
5
6
7
8
9
10
11
12
import { DataSource } from "typeorm";
import { typeormGCP, typeormLocal } from "typeormconfig";

export const databaseProviders = [
  {
    provide: "DATA_SOURCE",
    useFactory: async () => {
      const dataSource = new DataSource(typeormGCP);
      return dataSource.initialize();
    },
  },
];

위 코드는 sequelize 연결을 위한 코드이다. addModels에 정의한 entity를 넣어준다. export 한 provider는 database.module.ts에서 받아준다.

database.module.ts

1
2
3
4
5
import { Module } from "@nestjs/common";
import { databaseProviders } from "./database.provider";

@Module({ providers: [...databaseProviders], exports: [...databaseProviders] })
export class DatabaseModule {}

database 모듈 코드다. 모듈에 exports가 있는데, 제공받은 클래스를 export 해 준다. 여기까지 database 모듈에 대한 정의가 끝났다.

app.module.ts

1
2
3
4
5
6
7
8
9
10
import { Module } from "@nestjs/common";
import { UsersModule } from "./users/users.module";
import { DatabaseModule } from "./database/database.module";

@Module({
  imports: [UsersModule, DatabaseModule],
  controllers: [],
  providers: [],
})
export class AppModule {}

app 모듈에 database 모듈을 import 해준다. 위에서 생성한 users 모듈도 같이 import 한다.

users.provider.ts

1
2
3
4
5
6
7
8
9
import { DataSource } from "typeorm";
import { Users } from "./users.entity";
export const userProviders = [
  {
    provide: "USERS_REPOSITORY",
    useFactory: (dataSource: DataSource) => dataSource.getRepository(Users),
    inject: ["DATA_SOURCE"],
  },
];

service의 constructor에 정의될 provider이다. provider의 이름과 사용할 entity를 명시해 준다.

users.service.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { Inject, Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { insertUserDto } from './dto/insert.user.dto';
import { saveUserDto } from './dto/save.user.dto';
import { Users } from './users.entity';
import { v4 as uuid } from 'uuid';
import * as bcrypt from 'bcryptjs';
import { signIn } from './dto/signin.dto';

@Injectable()
export class UsersService {
    constructor(
        @Inject('USERS_REPOSITORY')
        private userRepository: Repository<Users>,
    ) {}

    async create(userDto: insertUserDto): Promise<Users> {
        // 사용자 등록 register
        const user_id = uuid();

        const salt = await bcrypt.genSalt();
        const hashedPassword = await bcrypt.hash(userDto.password, salt);

        const newUser: saveUserDto = {
            user_id: user_id,
            name: userDto.name,
            email: userDto.email,
            password: hashedPassword,
        };
        const user = this.userRepository.save({ ...newUser });
        return user;
    }
}

service에서는 데이터베이스에 직접 쿼리를 던진다. constructor에 데이터베이스의 provider를 정의한다. 이제UserService에서 User 테이블의 구조에 접근할 수 있다.

users.controller.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import {
    Body,
    Controller,
    Get,
    HttpStatus,
    Post,
    Res,
    UseFilters,
    UsePipes,
    ValidationPipe,
} from '@nestjs/common';
import { ApiBody, ApiResponse, ApiTags } from '@nestjs/swagger';
import { HttpExceptionFilter } from 'src/exception/http-exception.filter';
import { insertUserDto } from './dto/insert.user.dto';
import { signIn } from './dto/signin.dto';
import { Users } from './users.entity';
import { UsersService } from './users.service';

@ApiTags('users')
@Controller('users')
export class UsersController {
    constructor(private readonly userService: UsersService) {}

    @UseFilters(HttpExceptionFilter) //error handle
    @Post('registration') // http method
    @UsePipes(ValidationPipe) // validation pipe
    @ApiBody({ type: insertUserDto }) // swagger body
    @ApiResponse({ status: 200, description: 'user created' })
    async createUser(
        @Res() res: any,
        @Body() userDto: insertUserDto,
    ): Promise<void> {
        //   사용자 회원가입
        const user = await this.userService.create(userDto);
        res.status(HttpStatus.OK).json(user);
    }
}

controller에서는 라우팅 경로 정의와 client에서 넘어오는 값의 유효성 검사, api 문서 등을 정의할 수 있다. nest js의 데코레이터를 사용하게 됩니다. 자세한 동작에 대해서는 이후 포스팅에서 설명한다.

nest js에서 기본적인 3계층 구조를 봤다. 이제 client의 요청에 따른 동작을 구현할 수 있다. 다음 포스팅에서는 swagger api 문서를 생성하는 방법을 알아본다.

This post is licensed under CC BY 4.0 by the author.

NestJS 프로젝트 시작하기 with docker(1)

인공지능 웹 서비스 프로젝트 1주차 회고