Node.js/Nest.js

[Nest.js] TypeORM을 활용해 공식문서처럼 Repository 만들기

후뿡이 2023. 7. 2. 03:53

🐳 Repository 란 ?


먼저 Repository의 구현에 앞서 Repository란 무엇인지 알아보자.

Repository is just like EntityManager but its operations are limited to a concrete entity.
You can access the repository via EntityManager.

위의 글은 TypeORM 공식 문서의 Repository 설명이다.

즉 Repository는 구체적인 Entity에 대한 EntityManager이다. 그렇다면 EntityManager는 무엇일까 ?

Using EntityManager you can manage (insert, update, delete, load, etc.) any entity.
EntityManager is just like a collection of all entity repositories in a single place.

EntityManager는 Entity의 CRUD 작업을 도와주는 역할을 수행하고 이는 비지니스로직과 DB 사이의 새로운 계층을 의미한다고 볼 수 있다.

하지만 EntityManager는 Repository와는 다르게 모든 Entity에 접근이 가능하다는 차이점이 있다.

 

우리는 Repository를 이용해 특정 Entity의 DB에 접근하는 새로운 Layer를 구현해 보도록 하자 !

 

왜 새로운 Layer를 만들어야 하는가 ?

 

 

🐳 Nest.js 공식문서처럼 Repository 구현하기 


먼저 User Entity에 대한 Repository를 만들어 보자

 

# user.provider.ts

import { DataSource } from "typeorm";
import { User } from "./entity/user.entity";


export const userProviders = [
    {
        provide:'USER_REPOSITORY',
        useFactory:(dataSource:DataSource) => dataSource.getRepository(User),
        inject:['DATA_SOURCE'],
    }
];

 

먼저 위의 코드처럼 userProvider를 만들어 준다 ( 후에 user module에 provider로 주입해 준다 )

이 리스트는 객체를 가지고 있는데 이 객체는 provide의 이름과 dataSource를 활용해 Repository를 가져온다.

dataSource의 EntityManager가 모든 Entity의 DB 접근을 관리하는 역할을 한다는 것을 생각해 보면 DataSource에서 User Repository를 가져오는 것은 당연해 보인다.

 

이렇게 userProvider객체를 만들어 주었으면 아래의 코드처럼 provider로 의존성을 주입해 준다.

# user.module.ts

@Module({
    imports:[
        DatabaseModule,
        TypeOrmModule.forFeature([User]),
        JwtModule.register({
            secret:'jwt secret text',
            signOptions:{
                expiresIn:3600
            }
        }),
        PassportModule.register({defaultStrategy:'jwt'})

    ],
    controllers: [UsersController],
    # userProvider가 리스트 안에 객체가 있었으므로 spread 연산자를 통해 펼쳐 넣어 준다
    providers: [
        ...userProviders,
        UsersService,
        JwtStrategy
    ],
    exports:[JwtStrategy,PassportModule]
    
})

 

위와 같이 해줌으로써 의존성을 주입해 줄 수 있다.

 

그 다음은 user.service.ts에서 실제로 Repository를 가져오는 부분을 살펴보자

 

import { AuthCredentialDto } from './dto/auth-credential.dto';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class UsersService {
    constructor(
        @Inject('USER_REPOSITORY')
        private userRepository:Repository<User>,
        private jwtService:JwtService
    ) {}
}

 

위의 코드와 같이 constructor 를 통해 repository를 가지고 온다.

이 때 @Inject('USER_REPOSITORY') 의 경우 위에서 만든 userProvider 객체의 provide부분과 이름이 반드시 같아야 한다.

 

🐳 회고


처음 Nest.js를 접했을 때는 TypeORM도 처음이고 해서 Repository를 만들어야 한다는 필요성만 알고 방법을 몰라 구글을 뒤지던 도중 어떤 블로그를 보고 따라했다. 하지만 이전 TypeORM 버전 방법이었고 그 방법을 통해 Repository를 구현하니 Unit Testing에도 많은 어려움을 겪었다.

 

그래서 새롭게 게시판을 만들어 보는 프로젝트를 할 때는 공식문서를 활용해 만들어 보기로 다짐했다. 다행히 잘 찾아보니 어렵지 않게 만들어 볼 수 있었다.

 

이렇게 공식 문서를 탐방해 가며 구현해 보니 Repository의 개념과 Datasource의 역할 등 TypeORM에 대해 더 알게 되었다.

 

공부는 역시 단어의 정의부터 찾아가며 공부해야 하는 것 같다.

다음에 모르는게 나왔을 때는 해결방법부터 찾는 것이 아니라 내가 찾는 것의 역할부터 깊게 들여다 보는 습관이 필요할 것 같다,

 

🐳 자료출처


https://docs.nestjs.com/recipes/sql-typeorm

https://typeorm.io/working-with-repository