0. 개요
[ 기존의 구조 ]
보통 express에서는 컨트롤러, 서비스 별로 쭈욱 파일이 모여있다.
- 아래는 과거에 진행한 프로젝트 구조이다. 프로젝트를 진행하면서 mvp가 많아질수록 컨트롤러와 서비스는 많아졌고 점점 도메인 별로 코드를 찾기 어려워졌다.
- 이 구조는 서비스가 확장되면 도메인 별로 흩어져 있기 때문에 파일을 찾아서 개발하는 것이 힘들다.
그래서 좀 더 대규모 서비스의 폴더 구조는 어떻게 설계하는지 궁금해졌고, 이번에는 nest에서 최대한 DDD할 수 있는 폴더 구조를 알아보려 한다.
┣ 📂controllers
┃ ┣ 📜bookMarkController.ts
┃ ┣ 📜checklistController.ts
┃ ┣ 📜scheduleController.ts
┃ ┣ 📜subscribeController.ts
┃ ┣ 📜supplementController.ts
┃ ┗ 📜userController.ts
┣ 📂middlewares
┃ ┣ 📜errorMiddleware.ts
┃ ┣ 📜loginRequired.ts
┃ ┣ 📜validator.ts
┃ ┣ 📜verifyRefreshToken.ts
┃ ┗ 📜verifyToken.ts
┣ 📂routes
┃ ┣ 📜bookMarkRouter.ts
┃ ┣ 📜checklistRouter.ts
┃ ┣ 📜scheduleRouter.ts
┃ ┣ 📜subscribeRouter.ts
┃ ┣ 📜supplementRouter.ts
┃ ┗ 📜userRouter.ts
┣ 📂services
┃ ┣ 📜bookMarkService.ts
┃ ┣ 📜checklistService.ts
┃ ┣ 📜scheduleService.ts
┃ ┣ 📜subscribeService.ts
┃ ┣ 📜supplementService.ts
┃ ┗ 📜userService.ts
[ What is DDD? ]
Domain Driven Design의 약자로 도메인 주도 설계를 말한다.
🔅 Domain (도메인)이란?
1) 사전적의미: '영역', '집합'
2) DDD에서의 Domain: 비즈니스 Domain
3) 비즈니스 Domain: 유사한 업무의 집합
4) 애플리케이션은 비즈니스 Domain별로 나누어 설계 및 개발 될 수 있다.
nest에서 폴더구조를 세워보자!
1. 폴더 구조
이 구조는 일반적인 NestJS 구조가 아니라 새롭게 설정한 구조이다.
'구름톤' 해커톤에서 배운 구조이며 블로그를 참고했다.
(자세한 내용은 해당 블로그를 참고해주세용!)
src
├─auth
│ ├─decorators
│ ├─domain
│ ├─guards
│ └─helpers
├─common
│ ├─entities
│ ├─interfaces
│ └─repositories
├─config
│ ├─database
│ │ └─mysql
│ └─jwt
├─database
│ └─migrations
├─modules
│ └─user
│ └─users
│ ├─entities
│ └─repositories
└─providers
└─database
└─mysql
[ auth ]
인증과 관련된 기능을 작성하는 폴더이다.
[ common ]
공통으로 많이 사용되는 코드들 작성한다. 모든 폴더에서 정말 common하게 사용할 코드들이다.
[ config ]
기존에 프로젝트에서는 dotenv를 사용했는데 이번에는 @nest/config를 이용해서, 환경변수 설정한다.
현업에서는 test, dev, prod 등 여러 환경을 사용하게 되는데 그때마다 다른 환경 변수를 사용할 필요가 있다. @nestjs/config를 통해서 다양한 환경에 다양한 환경 변수를 사용하는 것이 좋다.
config를 관리하는 방법은 해당 블로그를 보고 따라해보자.
👉 Creating Config Files in NestJS
1) 패키지 설치
$ npm i --save @nestjs/config
2) 폴더 구조
src/
└── config/
├── app/
│ ├── config.module.ts
│ ├── config.service.ts
│ └── configuration.ts
│ └── index.ts
├── database/
│ └── mysql
│ ├── config.module.ts
│ ├── config.service.ts
│ └── configuration.ts
│ └── index.ts
└── mail/
├── config.module.ts
├── config.service.ts
└── configuration.ts
└── index.ts
- configuration.ts: 변수들을 등록해준다.
- configuration.service.ts: 'getter(획득자)' 기반 클래스 함수가 있는 단순한 클래스이다.
- 참고자료: 자바스크립트에서 getter과 setter
@Injectable()
export class MysqlConfigService {
constructor(private configService: ConfigService) {}
get host(): string {
return this.configService.get<string>('mysql.host');
}
}
- config.module.ts: 앱 구성 관련 클래스를 가져와서 제공한다.
3) 사용 방법
일반적으로 dotenv 방식이라면 다음과 같이 사용한다. (process.env.JWT_SECRET_KEY)
import dotenv from "dotenv";
dotenv.config();
const secretKey = process.env.JWT_SECRET_KEY;
// access token 발급
const makeToken = (Object: ITokenInput) => {
const token = jwt.sign(Object, secretKey, { expiresIn: "1h" });
return token;
};
지금 방식에서는 비즈니스 로직을 구현하는 곳에서 다음과 같이 ConfigService를 import한 뒤 this.config.get('환경 변수')로 사용할 수 있다.
> this.jwtConfig.accessSecretKey
import { JwtConfigService } from '@config/jwt';
@Injectable()
export class VerifyGuard implements CanActivate {
constructor(private readonly jwtConfig: JwtConfigService) {}
private _getPayload(req: Request) {
...
const payload = jwt.verify(token, this.jwtConfig.accessSecretKey);
}
}
[ database ]
migrations파일이 있는 폴더이다.
[ providers ]
외부 서비스(앱)를 말그대로 제공받는 폴더이다.
[ modules ]
비즈니스 로직을 구현하는 곳이다.
modules
└─user
│ user.module.ts
│
└─users
│ users.controller.ts
│ users.module.ts
│ users.service.ts
│
├─entities
│ index.ts
│ user.entity.ts
│
└─repositories
index.ts
user.repository.ts
이때 user 도메인으로 작성을 하더라도 그 안에서 세부적으로 나뉠 수 있기 때문에 세부적으로 나누고 연관된 도메인끼리 Aggregate한다.
예를 들어, User 객체가 있고, User가 하는 운동 UserActive, UserProfile 객체가 있다면 모두 하나의 Aggregate라고 할 수 있다.
가장 큰 도메인은 단수형, 세부적인 도메인은 복수형.
글이 점점 길어지고 있어 좀 더 자세한 @nest/config과 DDD Aggregate에 대해서는 따로 포스팅을 작성하겠다,
📌 Reference
'프로젝트 개발 기록 > [개발] node.js | nest, express' 카테고리의 다른 글
[Node.js] Nest.js에서 프로젝트 시작하기 (0) | 2022.09.14 |
---|---|
TypeScript + node.js에서 Jest로 단위테스트 하기 (0) | 2022.07.17 |
[TypeScript+Express] Redis로 Refresh Token 관리 (0) | 2022.06.21 |
[TypeScript + Express] Error handling (2) | 2022.06.17 |
댓글