작은 도서관
article thumbnail

사용 라이브러리

"@nestjs/typeorm": "^10.0.0",
"typeorm": "^0.3.17",
"bcrypt": "^5.1.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",

postgresql을 사용하는 이유

  postgresql mysql
아키텍처 객체 관계형 단일 관계
지원하는 데이터 타입 숫자
날짜(시간)
문자열
JSON
boolean
열거형
XML
기하형
배열
범위
네트워크 주소
숫자
날짜(시간)
문자열
JSON
공간(Spatial)
장점 복잡한 쿼리에 유용함
데이터베이스 크기에 제한이 없음
읽기-쓰기 속도가 빠름
확장에 유리함
광범위한 대중성
읽기 전용 명령을 사용할 수 있음

postgresql을 nestjs에 추가

app.module.ts파일에서 불러오는것으로 쉽게 사용할 수 있다.

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'postgres',
      password: '1234qwer',
      database: 'nestjsbackend',
      entities: [User],
      synchronize: true,
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

entities의 경우는 저렇게 불러와서 직접 채워넣어도 되고, 와일드카드('*.entity.ts'와 같은)를 이용해 작성할 수 있다.

필자는 등록되어있는 entity를 해당 파일에서 한 눈에 볼 수 있도록 불러와 사용하는 방식을 채택했다.

Entity와 DTO 생성

import {
  Entity,
  Column,
  CreateDateColumn,
  BeforeInsert,
  PrimaryColumn,
} from 'typeorm';
import * as bcrypt from 'bcrypt';

@Entity('user')
export class User {
  @PrimaryColumn({ nullable: false, unique: true, type: 'varchar' })
  id: string;

  @Column({ nullable: false, type: 'varchar' })
  password: string;

  @CreateDateColumn()
  createAt: Date;

  @BeforeInsert()
  async HashPassword(): Promise<void> {
    this.password = await bcrypt.hash(this.password, 10);
  }
}

User를 관리하는 Entity 파일이다.

id와 password가 있으며, mongodb처럼 timestamp를 따로 지원하지 않기 때문에 createAt이라는 칼럼을 만들어야한다.

이 Entity에선 단방향 암호화가 구현되어 있는데, 마지막 HashPassword가 그 역할을 한다.

typeorm에선 해당 데이터를 저장(insert)하기 전에 실행할 메서드를 BeforeInsert 데코레이터로 작성할 수 있다.

이 경우 해당 메서드에서 비밀번호를 bcrypt 라이브러리의 hash를 이용해 재 저장한다.

import { IsNotEmpty, IsString, MinLength } from 'class-validator';

export class CreateUserDto {
  @IsNotEmpty()
  @IsString()
  @MinLength(8, { message: '아이디는 8글자 이상이여야 합니다!' })
  readonly id: string;

  @IsNotEmpty()
  @IsString()
  readonly password: string;
}

export type UpdateUserDto = Partial<CreateUserDto>;

DTO는 위와 같이 작성하였다.

UpdateUserDto는 CreateUserDto의 Partial 타입으로서, 상위 타입의 모든 속성을 Optional로 변경하여 필요한 값만 업데이트 할 수 있도록 했다.

CRUD 구현

@Post()
async create(@Body() data: CreateUserDto): Promise<ResponseType> {
  const result = await this.userservice.createUser(data);
  return {
    message: '사용자가 성공적으로 생성되었습니다.',
    content: result,
  };
}

@Get('/:id')
async getOneUser(@Param('id') id: string): Promise<ResponseType> {
  const result = await this.userservice.findUser(id);
  return {
    message: '사용자 조회 결과입니다',
    content: result,
  };
}

@Get()
async getUser(): Promise<ResponseType> {
  const result = await this.userservice.findAllUser();
  return {
    message: '사용자 조회 결과입니다',
    content: result,
  };
}

@Patch('/:id')
async update(
  @Param('id') id: string,
  @Body() data: UpdateUserDto,
): Promise<ResponseType> {
  const result = await this.userservice.updateUser(id, data);
  return {
    message: '사용자 정보 수정 결과입니다.',
    content: result,
  };
}

@Delete('/:id')
async deleteUser(@Param('id') id: string): Promise<ResponseType> {
  const result = await this.userservice.deleteUser(id);
  return {
    message: '사용자 삭제 결과입니다.',
    content: result,
  };
}

컨트롤러 파일이다.

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

  createUser(data: CreateUserDto): Promise<User> {
    const user: User = new User();
    user.id = data.id;
    user.password = data.password;

    return this.userRepository.save(user);
  }

  findUser(data: string): Promise<User> {
    return this.userRepository.findOneBy({ id: data });
  }

  findAllUser(): Promise<User[]> {
    return this.userRepository.find();
  }

  deleteUser(data: string): Promise<DeleteResult> {
    return this.userRepository.delete({ id: data });
  }

  updateUser(id: string, data: UpdateUserDto): Promise<UpdateResult> {
    return this.userRepository.update({ id: id }, data);
  }
}

실제 api는 이렇게 되어있다.

눈여겨 보아야 할 곳은 생성자인데, User Entity를 토대로 repository라는 인터페이스를 생성한다.

repository에서 자체적으로 제공하는 메서드만으로 crud를 간단하게 구현할 수 있다.

'코딩 > 백엔드' 카테고리의 다른 글

[nestjs] 프로젝트에 prisma 추가하기  (2) 2023.10.20
[nestjs] 로그인과 권한 부여  (0) 2021.12.20
[nestjs] socket.io 사용과 테스트  (0) 2021.11.01
[koa] mongoose 연결 / CRUD  (1) 2021.10.07
profile

작은 도서관

@Flrea

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!