https://github.com/wanted-wecode-subjects/freshcode-subject
요구사항
ERD(Entity-Relationship Modelling)는 데이터 모델링 분야에서 사용하는 용어로 개체-관계 모델이라 하며,구조화된 데이터를 도식화 한 표현입니다.
ERD cloud는 DB 모델링 도구로 ERD 작성을 도와줍니다.
이번 프로젝트에서 팀원의 소개로 처음 사용해보았습니다.
커밋 메시지에 대한 형식을 두어 깔끔하게 작성하거나 다른 사람들이 읽기 쉽게끔 컨벤션을 둘 수 있습니다.
팀원과 상의하여 컨벤션을 정의할 수 있으며, 프로젝트 초기에 이를 작성하는 것이 좋습니다.
보통 일반적으로 첫째 줄에 제목을 적고, 둘째 줄부터 본문으로 취급하여 커밋에 대한 내용을 작성합니다.
feat
- 신규 기능 추가fix
- 버그 수정docs
- 문서 수정style
- 코딩 스타일 관련(로직 변경x)refactor
- 코드 리팩터링test
- 테스트 코드 관련ci
- CI/CD 관련chore
- 기타너무나 당연한 얘기지만 상속을 통해 클래스를 확장할 수 있습니다.
이번 프로젝트에서는 CoreEntity 라는 클래스를 두어 엔티티가 공통적으로 가지고 있는 createdAt, updatedAt, deletedAt 같은 컬럼을 갖도록 하고, 다른 엔티티 클래스에서 이를 상속하여 사용할 수 있도록 처리하였습니다.
ID 중복에 대한 상태코드를 찾던 중 다음 글(https://deveric.tistory.com/62) 찾게 되었습니다.
해당 글에서는 ID 중복에 대해 상태코드로 423, 403, 409 중 하나를 반환하려 하였으며, 그 중 409를 ID 중복에 대한 상태코드로 반환하게 되었습니다.
위의 각 상태코드에 대한 설명은 다음과 같습니다.
이로 미루어 볼 때, 423은 가입 이후 해당 리소스(ID)에 대한 잠금과는 무관하여 제외되어야 하고, 403은 ID 중복보다는 데이터 유효성이나 인가 실패에 사용하므로 제외되어야 합니다. 마지막으로 409는 리소스에 대한 충돌이므로 ID라는 PK 자원을 점유한 것에 대한 충돌이기 때문에 적합하다고 볼 수 있습니다.
@nestjs/config를 사용하여 환경변수를 가져올 수 있습니다.
외부에서 정의된 환경변수는 전역으로 선언된 process.env를 통해 확인할 수 있습니다. 또한 .env 파일에 정의된 key-value 값을 가져와서 사용할 수도 있습니다. .env 파일 안의 데이터 형태는 key=value
형태로 정의되어야 합니다.
이를 위해선 @nestjs/config 패키지를 설치하고, AppModule에서 ConfigModule을 import 합니다.
app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [ConfigModule.forRoot()],
})
export class AppModule {}
ConfigModule에 envFilePath를 두어 .env 파일의 경로를 직접 정의할 수 있습니다.
ConfigModule.forRoot({
envFilePath: ['.env.development.local', '.env.development'],
});
custom configuration file은 config 객체를 반환하는 팩토리 함수를 내보냅니다.
환경에 따라 적절한 변수 설정이 필요할 때 사용할 수 있습니다.
config/configuration.ts
export default () => ({
port: parseInt(process.env.PORT, 10) || 3000,
database: {
host: process.env.DATABASE_HOST,
port: parseInt(process.env.DATABASE_PORT, 10) || 5432
}
});
app.module.ts
import configuration from './config/configuration';
@Module({
imports: [
ConfigModule.forRoot({
load: [configuration],
}),
],
})
export class AppModule {}
출처: https://docs.nestjs.kr/techniques/configuration
일반적인 방법으로 env에서 값을 가져와 JwtModule의 secret으로 설정하면 에러가 발생합니다.
@Module({
imports: [
JwtModule.register({
secretOrPrivateKey: process.env.SECRET
})
]
})
이는 JwtModule이 인스턴스화 될 때 아직 env에서 해당 값을 가져오지 못해 발생하는 이슈이며, 이를 위해 JwtModule의 registerAsync를 사용하여 해결할 수 있습니다.
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
secretOrPrivateKey: configService.jwtSecret,
}),
inject: [ConfigService],
}),
테스트 코드에서 bcrypt 함수를 사용하는 경우가 있었습니다. 그러나 해당 함수에 대한 mock이 없어 테스트에 실패하였습니다.
이를 해결하기 위해 아래와 같이 코드를 작성하면 bcrypt.compare에 대한 mock을 생성할 수 있습니다.
const bcryptCompare = jest.fn().mockResolvedValue(true);
(bcrypt.compare as jest.Mock) = bcryptCompare;
출처: const bcryptCompare = jest.fn().mockResolvedValue(true);
(bcrypt.compare as jest.Mock) = bcryptCompare;
Role에 대한 데코레이터를 생성하여 보호하고자 하는 메소드에 데코레이터를 적용하였으나, user가 빈 값으로 출력되는 등의 정상적으로 동작하지 않는 이슈가 있었습니다.
이는 @UseGuards(JwtAuthGuard, RoleGuard) 같이 가드를 사용하지 않아서 발생한 이슈이며, 해당 데코레이터를 적용한 결과 context.switchToHttp().getRequest()
의 user 값을 잘 가져오는 것을 확인하였습니다.
@UseGuards(JwtAuthGuard, RolesGuard)
@Role(UserRole.admin)
...
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some((role) => user.roles?.includes(role));
}
}
출처: https://docs.nestjs.kr/security/authorization
이번 회고는 5F(Fact, Feeling, Feedback, Finding, Future action)에 의거하여 작성해보았습니다.
(출처: https://codechasseur.tistory.com/102)