nestjs에서 swagger사용시, generic 타입에 대한 response schema 처리
페이징 처리시 다음의 DTO를 사용하고 있습니다.
export class Pagination<T> {
@ApiProperty()
public results: T[];
@ApiProperty()
public page_total: number;
@ApiProperty()
public total: number;
constructor(paginationResults: PaginationResultInterface<T>) {
this.results = paginationResults.results;
this.page_total = paginationResults.results.length;
this.total = paginationResults.total;
}
}
다른 부분의 표현은 문제가 없는데, generic
타입인 public results: T[];
를 제대로 표현하지 못해서 아쉬움을 느끼고 있었습니다.
How to generate Generics DTOs with nestjs/swagger를 찾아서 적용하니 잘 표현 되네요.
적용 방법은 아래와 같습니다.
우선 신규 ApiOkResponsePaginated
데코레이터를 추가 합니다.
import {
ApiOkResponse,
getSchemaPath,
ApiExtraModels,
ApiProperty,
} from '@nestjs/swagger';
import { PaginationResultInterface } from './pagination.results.interface';
import { applyDecorators, Type } from '@nestjs/common';
export class Pagination<T> {
// 중요! ApiProperty 를 사용하지 않음
public results: T[];
@ApiProperty()
public page_total: number;
@ApiProperty()
public total: number;
constructor(paginationResults: PaginationResultInterface<T>) {
this.results = paginationResults.results;
this.page_total = paginationResults.results.length;
this.total = paginationResults.total;
}
}
// 데코레이터 추가
export const ApiOkResponsePaginated = <DataDto extends Type<unknown>>(
dataDto: DataDto
) =>
applyDecorators(
ApiExtraModels(Pagination, dataDto),
ApiOkResponse({
schema: {
allOf: [
{ $ref: getSchemaPath(Pagination) },
{
properties: {
data: {
type: 'array',
items: { $ref: getSchemaPath(dataDto) },
},
},
},
],
},
})
);
마지막으로 아래와 같이 사용하려는 컨트롤러에서 @ApiResponse
대신 @ApiOkResponsePaginated
를 사용합니다.
@ApiOperation({ summary: '아이템 상품 목록 조회' })
@ApiOkResponsePaginated(ItmPrdMRO) // ApiOkResponsePaginated와 함께 사용할 generic 타입 지정
@Get('prd/list')
async getItmPrdMPaginate(@Query() dto: FindByCondDto) {
return await this.itmPrdMService.getItmPrdMPaginate(dto);
}
설정을 하고 결과를 확인하면 아래와 같이 원하는 response schema를 확인 할 수 있습니다.
{
"page_total": 0,
"total": 0,
"data": [
{
"id": 0,
"admAdminMIdNm": "string",
"itmDcd": "string",
"imgPath": "string",
"itmWearDcdNm": "string",
"avlbStrtDt": "string",
"avlbEndDt": "string",
"appItmNm": "string",
"itmNm": "string",
"prdAmt": 0,
"modDtm": "string"
}
]
}