API 개발을 하다 보면 Swagger를 활용해서 명세를 관리하는 경우가 많다. 일반적으로 DTO 클래스와 Swagger 데코레이터를 활용하면, 명확한 키 값을 가지는 객체나 객체 배열의 형태로 쉽게 명세를 작성할 수 있다. 하지만 응답 데이터의 키 값이 동적으로 할당되는 경우에는 어떻게 Swagger 명세를 작성해야 할까? 이번 글에서는 이런 경우를 해결하는 방법을 살펴보겠다.
(모든 예시는 NestJS 환경에서 작성되었다.)
NestJS에서 API 작업을 할 때, DTO 클래스와 Swagger 데코레이터를 활용하면 API 응답의 명세 예시가 자동으로 생성된다. 예를 들어, 일반적인 객체 형태나 객체 배열을 반환하는 경우 다음과 같이 Swagger 명세를 작성할 수 있다.
export class ExampleDto {
@ApiProperty({ description: 'name', example: 'John Doe' })
name: string;
@ApiProperty({ description: 'city', example: 'seoul' })
city: string;
}
이런 DTO를 컨트롤러의 응답으로 지정하면 Swagger에서 자동으로 명세를 생성해준다. 하지만 키 값이 동적으로 할당되는 경우에는 어떻게 해야 할까?
동적으로 할당되는 키를 가진 객체를 Swagger에서 문서화하려면 @ApiExtraModels() 데코레이터와 @ApiProperty() 데코레이터를 활용하면 된다.
import { ApiExtraModels, ApiProperty, getSchemaPath } from '@nestjs/swagger';
export class ExampleDto {
@ApiProperty({ description: 'name', example: 'John Doe' })
name: string;
@ApiProperty({ description: 'city', example: 'seoul' })
city: string;
}
// Swagger에서 동적 키 객체를 문서화하기 위해 DTO를 등록
// @ApiExtraModels()는 해당 Dto를 주입받는 객체에 달아줘야한다!
@ApiExtraModels(ExampleDto)
export class DynamicKeyExampleDto {
@ApiProperty({
description: '동적 키를 가지는 객체',
type: 'object',
additionalProperties: {
$ref: getSchemaPath(ExampleDto),
},
})
dynamicDto: { [id: string]: ExampleDto };
}
위와 같이 @ApiProperty()의 additionalProperties 옵션을 사용하면, 동적인 키를 가지는 객체 형태의 응답 명세를 Swagger에서 정의할 수 있다.

이 방식은 유용하지만 한 가지 단점이 있다. Swagger UI에서 동적으로 할당되는 키 값이 additionalProp1, additionalProp2 등의 형태로 고정되며, 이를 수정할 수 없다. 따라서 실제 API 응답에서는 원하는 키 값을 사용할 수 있지만, Swagger 문서에서는 제한이 있다는 점을 인지하고 활용해야 한다.
하지만 이는 Swagger 문서의 description을 통해 추가적인 설명을 명세에 포함하거나, 이해를 도울 수 있도록 예상되는 동적 키의 예시를 추가함으로써 충분히 해결할 수 있는 문제라고 생각된다.
동적으로 할당되는 키를 가지는 객체의 Swagger 명세를 작성하려면 @ApiExtraModels()와 @ApiProperty()의 additionalProperties 속성을 활용하면 된다. 이를 통해 명확한 API 문서를 유지하면서도, 유연하게 키 값이 동적인 객체를 다룰 수 있다. 다만, Swagger UI에서 키 값을 변경할 수 없다는 단점이 있으므로, 이를 감안해서 API 문서를 활용하는 것이 중요하다.