NestJS
Entityrepository()를 대신한 Repository 생성
2023-03-04포스팅 시점 nestjs 버전 : 9.x.x
새로운 토이 프로젝트를 만들면서 백엔드를 구축할 프레임워크로 nestjs를 이용하기로 마음먹었다.
원래 사용하고 있던 javascript/typescript와 동일한 언어를 사용하기 때문에 백엔드 구축에 비교적 진입장벽이 낮다고 생각했기 때문에다.
nest 작동순서
request -> controller -> service -> controller -> response 순으로 작동하나, DB와 관련된 일을 시키기 위해서는 repository를 생성해야한다고 한다. 즉,
request -> controller -> service -> repo* -> service -> controller -> response 로 한 단계가 추가된다. (Repostitory pattern)
@EntityRepository를 통해 레포지토리를 설정해주는 방식이 많이 보였지만
현재 버전에서는 사용할 수 없어 다른 방법을 알아봤다.
기본 설정
config 설정
// src/configs/typeorm.configs.ts export const typeORMConfig: TypeOrmModuleOptions = { // Database Type type: "postgres", // 본인은 pg를 사용 host: "localhost", port: 5432, username: "postgres", password: "password", database: "database", entities: [__dirname + "/../**/*.entity.{js,ts}"], // 해당 경로 + 엔티티이름.entity.{js.ts}로 된 엔티티를 이용 // autoLoadEntities: true, // 위와 다르게 entity들 알아서 찾아줌 synchronize: true, // @@@@@@@@ 배포할때 true 사용 시 데이터 삭제될 수 있음. production 단계에서는 필히 false로 해줄 것 권장 @@@@@@ };
config 설정 후 root 모듈에 import
// app.module.ts import { Module } from "@nestjs/common"; import { AppController } from "./app.controller"; import { PostlistModule } from "./postlist/postlist.module"; import { typeORMConfig } from "./configs/typeorm.configs"; import { TypeOrmModule } from "@nestjs/typeorm/dist"; @Module({ imports: [TypeOrmModule.forRoot(typeORMConfig), PostlistModule], controllers: [AppController], providers: [], }) export class AppModule {}
entity 생성
// src/postlist/entities/postlist.entity.ts import { BaseEntity, Column, PrimaryGeneratedColumn, Entity } from "typeorm"; @Entity() export class Postlist extends BaseEntity { @PrimaryGeneratedColumn() id: number; @Column() title: string; @Column() content: string; @Column() nickname: string; @Column() imageUrl?: string; }
config 설정 시 entities에 이름을 ~~.entity.{js.ts} 로 설정해놓고, 정작 entity 파일 이름을 설정한 형식과 다르게 작성하면 [EntityMetadataNotFound] 에러를 띄우게 되기 때문에 설정한대로 이름을 지어줘야 한다.
참조 : https://github.com/typeorm/typeorm/issues/1327
custumRepository 만들기
본인은 src에 database 디렉토리를 만들어, 데코레이터와 모듈을 그 안에 넣어줬다.
// src/database/typeorm-ex.decorator.ts import { SetMetadata } from "@nestjs/common"; export const TYPEORM_EX_CUSTOM_REPOSITORY = "TYPEORM_EX_CUSTOM_REPOSITORY"; export function CustomRepository(entity: Function): ClassDecorator { return SetMetadata(TYPEORM_EX_CUSTOM_REPOSITORY, entity); } // typeorm-ex.module.ts import { DynamicModule, Provider } from "@nestjs/common"; import { getDataSourceToken } from "@nestjs/typeorm"; import { DataSource } from "typeorm"; import { TYPEORM_EX_CUSTOM_REPOSITORY } from "./typeorm-ex.decorator"; export class TypeOrmExModule { public static forCustomRepository<T extends new (...args: any[]) => any>( repositories: T[], ): DynamicModule { const providers: Provider[] = []; for (const repository of repositories) { const entity = Reflect.getMetadata( TYPEORM_EX_CUSTOM_REPOSITORY, repository, ); if (!entity) { continue; } providers.push({ inject: [getDataSourceToken()], provide: repository, useFactory: (dataSource: DataSource): typeof repository => { const baseRepository = dataSource.getRepository<any>(entity); return new repository( baseRepository.target, baseRepository.manager, baseRepository.queryRunner, ); }, }); } return { exports: providers, module: TypeOrmExModule, providers, }; } }
사용할 repository 생성
// src/postlist/repository/postlist.repository.ts import { CustomRepository } from "src/database/typeorm-ex.decorator"; import { Repository } from "typeorm"; import { Postlist } from "../entities/postlist.entity"; @CustomRepository(Postlist) export class PostlistRepository extends Repository<Postlist> {}
module에 생성한 repository import
// src/postlist/postlist.module.ts import { Module } from "@nestjs/common"; import { PostlistController } from "./postlist.controller"; import { PostlistService } from "./postlist.service"; import { PostlistRepository } from "./repository/postlist.repository"; import { TypeOrmExModule } from "src/database/typeorm-ex.module"; @Module({ imports: [TypeOrmExModule.forCustomRepository([PostlistRepository])], controllers: [PostlistController], providers: [PostlistService], }) export class PostlistModule {}
Module에 import 후 service 비즈니스 로직에만 repository를 넣어주면 된다.
// src/postlist/postlist.service.ts import { Injectable, NotFoundException } from "@nestjs/common"; import { UpdatePostDto } from "./dto/update-postlist.dto"; import { PostlistRepository } from "./repository/postlist.repository"; import { Postlist } from "./entities/postlist.entity"; import { CreatePostDto } from "./dto/create-postlist.dto"; @Injectable() export class PostlistService { constructor(private readonly postlistRepository: PostlistRepository) {} async getAllPost(): Promise<Postlist[]> { const found = await this.postlistRepository.find(); return found; } async getPostById(id: number): Promise<Postlist> { const found = await this.postlistRepository.findOne({ where: { id: id } }); if (!found) { throw new NotFoundException(`Cannot find post with id ${id}`); } return found; } } // src/postlist/postlist.controller.ts import { Body, Controller, Get, Param, Patch, Post } from "@nestjs/common"; import { CreatePostDto } from "./dto/create-postlist.dto"; import { PostlistService } from "./postlist.service"; import { UpdatePostDto } from "./dto/update-postlist.dto"; import { Delete } from "@nestjs/common/decorators"; import { Postlist } from "./entities/postlist.entity"; @Controller("postlist") export class PostlistController { constructor(readonly postlistService: PostlistService) {} @Post() createOne(@Body() createPostDto: CreatePostDto): Promise<Postlist> { return this.postlistService.createPost(createPostDto); } @Get() getAll(): Promise<Postlist[]> { return this.postlistService.getAllPost(); } @Get(":id") getOne(@Param("id") id: number): Promise<Postlist> { return this.postlistService.getPostById(id); } @Patch(":id") updateOne( @Param("id") id: number, @Body() updateData: UpdatePostDto, ): Promise<Postlist> { return this.postlistService.updatePost(id, updateData); } @Delete(":id") deleteOne(@Param("id") id: number): Promise<void> { return this.postlistService.deletePost(id); } }
필요한 로직을 설정한 후 postman을 작동시켜주면 정상적으로 실행되는 것을 볼 수 있다.
nextjs와 동시에 작업하기 위해 nestjs 포트를 3001로 설정했지만, 보통은 nest 설치 시 app에 3000으로 설정된다.
DB는 postgreSQL을 이용했다. 정상적으로 테이블에 있는 데이터가 추출되는 것이 잘 확인된다.
참고 :
NestJS 카테고리의 다른 글
COMMENTS