본문 바로가기
nest.js

practice 1

by csue 2021. 9. 27.

basic

nest g resource 를 이용하면 CRUD entry points 를 포함한 대부분의 기본적인 보일러 플레이트들을 자동으로 생성해준다. 해당 resource 의 이름을 TestUser 라고 가정하자.

# 예시

:~/environment $ nest g resource
? What name would you like to use for this resource (plural, e.g., "
users")? test-user
? What transport layer do you use? REST API
? Would you like to generate CRUD entry points? Yes
CREATE test-user/test-user.controller.spec.ts (598 bytes)
CREATE test-user/test-user.controller.ts (971 bytes)
CREATE test-user/test-user.module.ts (270 bytes)
CREATE test-user/test-user.service.spec.ts (475 bytes)
CREATE test-user/test-user.service.ts (665 bytes)
CREATE test-user/dto/create-test-user.dto.ts (34 bytes)
CREATE test-user/dto/update-test-user.dto.ts (186 bytes)
CREATE test-user/entities/test-user.entity.ts (25 bytes)

 

# tree

test-user
    ├── dto
    │   ├── create-test-user.dto.ts
    │   └── update-test-user.dto.ts
    ├── entities
    │   └── test-user.entity.ts
    ├── test-user.controller.spec.ts
    ├── test-user.controller.ts
    ├── test-user.module.ts
    ├── test-user.service.spec.ts
    └── test-user.service.ts

 

생성된 resource 를 통해 간단한 CRUD 를 구현해보자.

test-user.entity.ts 에 db 와 연결되는 model 을 작성한다. 사용된 ORM 은 sequelize 이다.

 

// test-user/entities/test-user.entity.ts

...
@Table({
  tableName: "tb_test_user",
  paranoid: true, // deletedAt column 을 생성하여 실제로 삭제되지 않았으나 삭제된 것처럼 구현할 수 있게 해준다
  freezeTableName: true, // TableName을 Model을 설정할 때의 이름 그대로 사용하게 해준다 ... false 일 경우 복수형으로 변경된다
  timestamps: true, // 테이블을 생성한 후 자동적으로 createdAt, updatedAt column 을 생성한다
})

export class TestUser extends Model {
  @Column({
    primaryKey: true,
    type: DataType.STRING(14),
  })
  user_no!: string;

  @Column({
    type: DataType.STRING(50),
    allowNull: false,
  })
  user_id!: string;
...

 

엔터티에서 export 시킨 TestUser 클래스를 SequelizeModule.forFeature() method 를 사용하여 모듈에 imports 시켜주어야 한다. #이유

imports 시켜주지 않을 경우, ERROR [ExceptionHandler] Nest can't resolve dependencies of the TestUserService... 라는 dependency 에러를 만날 수 있다.

 

// test-user/test-user.module.ts 

import { Module } from "@nestjs/common";
import { TestUserService } from "./test-user.service";
import { TestUserController } from "./test-user.controller";
import { TestUser } from "./test-user.entity";
import { SequelizeModule } from "@nestjs/sequelize";

@Module({
  imports: [SequelizeModule.forFeature([TestUser])],
  controllers: [TestUserController],
  providers: [TestUserService],
})
export class TestUsersModule {}

 

SequelizeModule.forFeature() method 를 통해 정의한 모델은 service 레이어에서 InjectModel() 데코레이터를 통하여 inject 해줄 수 있다.

아래의 모습과 같다.

 

// test-user/test-user.service.ts 

import { Injectable } from "@nestjs/common";
import { InjectModel } from "@nestjs/sequelize";
import { Sequelize } from "sequelize-typescript";

import { CreateTestUserDto } from "./dto/create-test-user.dto";
import { UpdateTestUserDto } from "./dto/update-test-user.dto";
import { TestUser } from "./test-user.entity";

@Injectable()
export class TestUserService {
  constructor(
    @InjectModel(TestUser)
    private readonly testuserModel: typeof TestUser,
    private readonly sequelize: Sequelize
  ) {}
...

 

위에서 정의해 둔 모델을 통해 유저 정보를 가져오는 logic 을 생성해보자.

먼저 service layer 에서 sequelize where 절을 이용하여 user_no 가 같은 것을 가져오는 findOne 함수를 생성한다. controller 에서 들어온 요청을 service layer 의 findOne 함수로 리턴해주면 함수 내부에 정의된 logic 을 수행한다.

 

// test-user/test-user.service.ts 

...
findOne(user_no: string) {
    const user = this.testuserModel.findOne({
      where: {
        user_no: user_no,
      },
    });

    return user;
  }
...

 

// test-user/test-user.controller.ts

import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  UseGuards,
} from "@nestjs/common";
import { TestUserService } from './test-user.service';
import { CreateTestUserDto } from './dto/create-test-user.dto';
import { UpdateTestUserDto } from './dto/update-test-user.dto';

@Controller('test-user')
export class TestUserController {
  constructor(private readonly testUserService: TestUserService) {}

  @Get('/:user_no')
  findOne(@Param("user_no") user_no: string) {
    return this.testUserService.findOne(user_no);
  }
}

 

controller 는 엔드포인트로, 들어오는 parameter 와 그 타입을 설정할 수 있다. resource 를 생성하고 난 직후의 controller 는 아래의 형태로 생겼다. HTTP request method 를 설정하기 위해서 @Get 과 같은 형태의 HTTP request method decorator 를 사용한다.

@Param decorator 를 사용하여 parameter 값을 설정한다. query parameter 를 설정할 때에는 @Query decorator 를 사용한다.

이번에는 유저를 생성하는 logic 을 생성해보자. dto 단에 유저 생성을 위한 parameter 값들을 따로 정의한 CreateTestUserDto 클래스를 생성한다.

 

// test-user/dto/create-test-user.dto.ts

import { IsString } from "class-validator";

export class CreateTestUserDto {
  @IsString()
  readonly user_id!: string;

  @IsString()
  readonly password!: string;
}

 

export 시킨 CreateTestUserDto 클래스를 이용하여 request 의 @Body 를 통해 들어오는 값들을 정의해 둔 createTestUserDto 에 담아 service layer 에 위치한 create 함수로 보내면, 함수 내부에 정의된 logic 을 수행하여 user 정보를 create 해준다.

 

// test-user/test-user.contoller.ts

...
@Post()
  create(@Body() createTestUserDto: CreateTestUserDto) {
    return this.testUserService.create(createTestUserDto);
  }

 

// test-user/test-user.service.ts 

...
create(createTestUserDto: CreateTestUserDto) {
    const dto = {
      ...createTestUserDto,
    };

    return this.testuserModel.create(dto);
  }
...

'nest.js' 카테고리의 다른 글

practice 2  (0) 2021.09.27
Nest.js  (0) 2021.07.22