class-validator
와 @nestjs/swagger
의 데코레이터를 함께 사용합니다."이 API를 호출할 때, 이런 데이터 구조로 보내주세요!"
또는
"서버는 이런 데이터 구조로 응답해줄게요!"
라고 약속된 데이터의 형태를 정의하는 거예요.
CreateBoardDto
import { ApiProperty } from '@nestjs/swagger';
import { MaxLength, MinLength, IsNotEmpty } from 'class-validator';
export class CreateBoardDto {
@MinLength(2)
@MaxLength(20)
@IsNotEmpty()
@ApiProperty({
description: '이름',
required: true,
example: '홍길동',
})
name: string;
@IsNotEmpty()
@ApiProperty({
description: '내용',
required: true,
example: '내용입니다.',
})
content: string;
}
UpdateBoardDto
(부분 수정 가능)import { IsOptional, MaxLength, MinLength } from 'class-validator';
export class UpdateBoardDto {
@MinLength(2)
@MaxLength(20)
@IsOptional()
name?: string;
@IsOptional()
contents?: string;
}
HttpExceptionFilter
import {
ExceptionFilter,
ArgumentsHost,
HttpException,
Catch,
} from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: ctx.getRequest<Request>().url,
});
}
}
main.ts
에서 아래와 같이 등록합니다.
import { HttpExceptionFilter } from './exceptions/http.exceptions';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
// ...생략
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
LoggingMiddleware
import { Injectable, Logger, NestMiddleware } from '@nestjs/common';
import { NextFunction, Request, Response } from 'express';
@Injectable()
export class LoggingMiddleware implements NestMiddleware {
private readonly logger = new Logger();
use(req: Request, res: Response, next: NextFunction) {
const { method, originalUrl } = req;
const startTime = Date.now();
res.on('finish', () => {
const { statusCode } = res;
const responseTime = Date.now() - startTime;
this.logger.log(
`[${method}] ${originalUrl}: ${statusCode} ${responseTime}ms`,
);
});
next();
}
}
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { LoggingMiddleware } from './middleware/logging.middleware';
@Module({
// ...생략
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggingMiddleware).forRoutes('*');
}
}
npm install @nestjs/config
src/config/configuration.ts
export default () => ({
ENVIRONMENT: process.env.ENVIRONMENT,
});
src/config/index.ts
import { ConfigModule } from '@nestjs/config';
import configuration from './configuration';
export default ({} = {}) =>
ConfigModule.forRoot({
isGlobal: true,
envFilePath: `.env.local`,
load: [configuration],
});
import ConfigModule from './config';
@Module({
imports: [ConfigModule() /* ...다른 모듈 */],
// ...
})
export class AppModule implements NestModule {
// ...
}
npm install class-validator class-transformer @nestjs/config @nestjs/swagger