μλ²λ¦¬μ€ νκ²½μμ Swagger DTO νμ λ¬Έμ ν΄κ²° λ° μ¬μ© ν¨ν΄ κ°μ νκΈ°
- #nestjs
- #api docs
- #swagger
- #serverless
- #bundling
- #microservice
- #dto
λ€μ΄κ°λ©°
μλ νμΈμ. λ Έλ¨Έμ€ λ°±μλ μμ§λμ΄ μμΉνμ λλ€.
μ΄λ² κΈμμλ μλ²λ¦¬μ€ λ§μ΄ν¬λ‘μλΉμ€ νκ²½μμ Swaggerλ₯Ό ν΅ν΄ API λ¬Έμλ₯Ό κ΄λ¦¬νλ©° κ²ͺμλ μ΄μμ ν΄κ²° κ³Όμ μ 곡μ νκ³ μ ν©λλ€. λ²λ€λ§ νκ²½μμ DTO ν΄λμ€λͺ μ΄ μλν λλ‘ νμλμ§ μλ λ¬Έμ λ₯Ό λ°κ²¬νκ³ , μ΄λ₯Ό κ³κΈ°λ‘ Swagger μ¬μ© ν¨ν΄ μ λ°μ μ κ²νκ³ κ°μ ν μ μμμ΅λλ€.
κ°μ μ κ³κΈ°
μ΄μ μ π Serverless λ§μ΄ν¬λ‘μλΉμ€ νκ²½μμ API Docs ν΅ν©νκΈ°μμ μκ°ν΄λλ¦° κ²μ²λΌ λ Έλ¨Έμ€μμλ Swagger UIλ₯Ό μ¬μ©ν΄ API Docsλ₯Ό ꡬμ±νκ³ μμ΅λλ€.
μλ²λ¦¬μ€ νκ²½μμ λ²λ€λ§μ κ±°μ³ λ°°ν¬νλ κ³Όμ μμ Swagger UIκ° μ μλνλ κ²μ²λΌ 보μμ§λ§, νλ‘ νΈμλ νκ³Ό OpenAPI μ€νμ 곡μ νμ¬ νμ μ μλ μμ±νλ ν μ€νΈλ₯Ό μ§ννλ μ€ μμμΉ λͺ»ν λ¬Έμ λ₯Ό λ°κ²¬νμ΅λλ€. λ°°ν¬ ν Swagger λ¬Έμμμ DTO ν΄λμ€λͺ μ΄ μ°λ¦¬κ° μ μν μ΄λ¦λλ‘ νμλμ§ μλ κ²μ΄μμ΅λλ€.
λ°κ²¬ν λ¬Έμ μ λ€
Swagger λ¬Έμλ₯Ό μμΈν μ κ²νλ©° λ°κ²¬ν λ¬Έμ μ μ ν¬κ² λ€ κ°μ§μμ΅λλ€.
1. λ²λ€λ§ μ ν΄λμ€λͺ νμ μ΄μ
λ°°ν¬ ν Swagger UIλ₯Ό νμΈνλ, μ°λ¦¬κ° μ μν DTO ν΄λμ€λͺ μ΄ μλν λλ‘ νμλμ§ μμμ΅λλ€.
λ°°ν¬ νκ²½μ Swagger UIμμ λ€μκ³Ό κ°μ νμλ€μ΄ λ°κ²¬λμμ΅λλ€:
CreateOrderDtoκ°CreateOrderDto1,_CreateOrderDtoλ± μλνμ§ μμ λ¬Έμκ° λΆμ΄μ νμGetProductQueryκ°Objectλλ μλ―Έ μλ μ΄λ¦μΌλ‘ νμ- κ°μ DTOκ° μ¬λ¬ λ² μ μλμ΄ Swagger λ¬Έμκ° λ³΅μ‘ν΄μ§

λΉμ Swagger λ¬Έμλ₯Ό OpenAPI μ€νμΌλ‘ exportνμ¬ νλ‘ νΈμλ νκ³Ό νμ
μ 곡μ νκΈ° μν μ€λΉλ₯Ό νκ³ μμμ΅λλ€. μ μ΄λ―Έμ§μ²λΌ [object Object] κ°μ νμ
μ΄ μμ±λλ©΄ νλ‘ νΈμλμμ TypeScript νμ
μ μλ μμ±ν λ μ€μ μ»΄νμΌ μ€λ₯κ° λ°μν©λλ€. DTO μ΄λ¦μ΄ CreateOrderDto1, Object κ°μ ννλ‘ μμ±λλ©΄ μ½λμμ νμ©νκΈ° μ΄λ ΅κΈ° λλ¬Έμ, λ°±μλμ νλ‘ νΈμλ κ° νμ
곡μ λΌλ λͺ©νλ₯Ό λ¬μ±νκΈ° μν΄μλ λ°λμ ν΄κ²°μ΄ νμνμ΅λλ€.
μμΈ:
μ΄λ¬ν νμμ esbuild λ± λ²λ€λ¬κ° μ½λλ₯Ό μ΅μ ννλ κ³Όμ μμ ν΄λμ€μ λ©νλ°μ΄ν°κ° μμ€λκ±°λ λ³κ²½λκΈ° λλ¬Έμ λ°μν©λλ€. Swaggerλ λ°νμμ ν΄λμ€ μ΄λ¦μ μ½μ΄μ λ¬Έμμ νμνλλ°, λ²λ€λ§ νμλ ν΄λμ€ μ λ³΄κ° μ λλ‘ μ λ¬λμ§ μμ Swaggerκ° μ€λ³΅μ νΌνκΈ° μν΄ μλμΌλ‘ μ«μλ₯Ό λΆμ΄κ² λ©λλ€.
// μ°λ¦¬κ° μμ±ν μ½λ
export class CreateOrderDto {
// ...
}
export class GetGoodsOptionsResponse {
// ...
}
// Swaggerμμ νμλλ μ΄λ¦
CreateOrderDto1 // μλνμ§ μμ μ΄λ¦
_GetGoodsOptionsResponse // μΈλμ€μ½μ΄κ° λΆκ±°λ
Object // μμ μλ―Έ μλ μ΄λ¦μΌλ‘ λ³κ²½
// νλ‘ νΈμλμμ μλ μμ±λ νμ
interface CreateOrderDto1 { // μ΄λ° νμ
μ νμ©νκΈ° μ΄λ €μ
// ...
}
interface _GetGoodsOptionsResponse { // μμμΉ λͺ»ν λ€μ΄λ°
// ...
}
2. Controllerμ DTO κ° λ°μ½λ μ΄ν° κ΄λ¦¬
μλΉμ€ μ΄κΈ°μλ Swagger μ¬μ© ν¨ν΄μ λ°λΌ @ApiQuery, @ApiParam, @ApiHeader λ±μ λ°μ½λ μ΄ν°λ₯Ό Controllerμ μ§μ μ μΈνκ³ μμμ΅λλ€. νμ§λ§ μλΉμ€κ° μ±μ₯νλ©΄μ DTO μ€μ¬μΌλ‘ API μ€νμ κ΄λ¦¬νλ κ²μ΄ λ ν¨μ¨μ μ΄λΌλ κ²μ μκ² λμμ΅λλ€. μ΄κΈ°μ μ κ·Ό λ°©μμ κ·Έλλ‘ μ μ§νλ©΄μ μλ‘μ΄ μ½λκ° μΆκ°λλ€ λ³΄λ λ€μκ³Ό κ°μ λ¬Έμ κ° μμμ΅λλ€:
- κ°μ μ 보λ₯Ό Controllerμ DTO μμͺ½μμ κ΄λ¦¬
- DTO λ³κ²½ μ Controller λ°μ½λ μ΄ν°λ ν¨κ» μμ ν΄μΌ νλ λ²κ±°λ‘μ
- λ―Έμ¬μ© μμ±λ€μ΄ κ³μ λ¨μμμ΄ λ¬Έμλ₯Ό λ λͺ ννκ² λ§λ€ νμ
3. νμ νκΈ° λ°©μ ν΅μΌ
μλΉμ€ μ΄κΈ°μλ Swagger λ¬Έμνμ λν λͺ νν κ°μ΄λκ° μμκ³ , κ°μμ λ°©μμΌλ‘ μμ±νλ€ λ³΄λ λ€μν μμ± ν¨ν΄μ΄ 곡쑴νκ² λμμ΅λλ€. μκ°μ΄ μ§λλ©° κΆμ₯λλ μμ± λ°©μμ΄ λ°μ νμ§λ§ κΈ°μ‘΄ μ½λλ μ λ°μ΄νΈλμ§ μμ ν΅μΌμ΄ νμνμ΅λλ€:
type: Numbervstype: 'number'λ± νμ μ§μ λ°©μμ μ°¨μ΄- empty arrayλ₯Ό κΈ°λ³Έκ°μ΄λ μμ λ‘ μ¬μ©ν μΌμ΄μ€ μ‘΄μ¬
- μ€λͺ (description)μ μΆκ°νλ©΄ λ λͺ νν΄μ§ DTO νλλ€
- Headerμ μΈμ΄ νλ λ± κ³΅ν΅ νμ μ μλΉμ€λ³ ν΅μΌ νμ
4. Union νμ μλ΅ μ²λ¦¬
μ½λλ² μ΄μ€λ₯Ό μ κ²νλ μ€, μΌλΆ APIμ μλ΅ νμ μ΄ Union νμ μΌλ‘ μ μλμ΄ μλ κ²μ λ°κ²¬νμ΅λλ€. Swaggerμ oneOf μ€νμ μ¬λ¬ μλ΅ νμ μ€ νλλ₯Ό λ°νν μ μμμ νννμ§λ§, μ€μ λ‘ OpenAPI μ€νμμ νμ μ μμ±ν λλ νλμ νμ μΌλ‘λ§ μΆλ‘ λλ κ²½μ°κ° μμ΄ νλ‘ νΈμλμμ μ νν νμ μ 보λ₯Ό λ°κΈ° μ΄λ €μΈ μ μμ΅λλ€.

μ΄ 3κ° λ©μλκ° μλ΅ μμ²΄κ° oneOf/Union νμ μΌλ‘ μ μλμ΄ μμμ΅λλ€. μ΄ λ¬Έμ μ ν΄κ²° λ°©λ²μ μλ 6. κ³΅ν΅ Response λνΌ νμ μ²λ¦¬ κ°μ μμ λ€λ£Ήλλ€.
κ°μ λ°©λ²
λ°κ²¬ν λ¬Έμ λ€μ ν΄κ²°νκΈ° μν΄ λ€μκ³Ό κ°μ μμ μ μ§ννμ΅λλ€.
1. @ApiSchema λ°μ½λ μ΄ν°λ‘ ν΄λμ€λͺ λͺ μμ μ§μ
λͺ¨λ DTO ν΄λμ€μ @ApiSchema() λ°μ½λ μ΄ν°λ₯Ό μΆκ°νκ³ , ν΄λμ€λͺ
μ λͺ
μμ μΌλ‘ μ§μ νμ¬ λ²λ€λ§ νμλ μ¬λ°λ₯Έ μ΄λ¦μ΄ μ μ§λλλ‘ νμ΅λλ€.
@ApiSchema({ name: 'CreateOrderDto' })
export class CreateOrderDto {
@ApiProperty({ type: 'string', description: 'μλ ΉμΈ μ΄λ¦' })
recipientName: string;
}
μ΄λ κ² νλ©΄ λ²λ€λ§ κ³Όμ μμ ν΄λμ€λͺ
μ΄ λ³κ²½λλλΌλ Swaggerλ μ°λ¦¬κ° μ§μ ν 'CreateOrderDto' μ΄λ¦μ μ¬μ©νμ¬ λ¬Έμμ νμν©λλ€. λ μ΄μ CreateOrderDto1, CreateOrderDto2λ Object κ°μ μλ―Έ μλ μ΄λ¦μ΄ λνλμ§ μμ΅λλ€.
μ΄ μμ μ μ§ννλ©΄μ Swaggerλ κ°μ μ΄λ¦μ DTOκ° μ¬λ¬ κ° μ‘΄μ¬ν κ²½μ° νλλ§ μ²λ¦¬νλ€λ μ μ μ μνμ΅λλ€. λ§μ΄ν¬λ‘μλΉμ€ νκ²½μμλ μλΉμ€ κ° DTO μ΄λ¦μ΄ μ€λ³΅λμ§ μλλ‘ λ€μ΄λ° κ·μΉμ μ νλ©΄μ μμ νμ΅λλ€.
2. Controller λ°μ½λ μ΄ν°λ₯Ό DTOλ‘ μ΄μ
κΈ°μ‘΄μ Controllerμ ν©μ΄μ Έ μλ @ApiQuery, @ApiParam, @ApiHeaderλ₯Ό DTOλ‘ ν΅ν©νμ΅λλ€.
λ³κ²½ μ :
@Get()
@ApiHeader({ name: 'lang' })
@ApiQuery({ name: 'productId', type: 'number' })
async getProduct(@Headers('lang') lang: string, @Query('productId') id: number) {
// ...
}
λ³κ²½ ν:
@Get()
async getProduct(@Headers() headers: GetProductHeaders, @Query() query: GetProductQuery) {
// ...
}
Controllerκ° κ°κ²°ν΄μ§κ³ , DTOλ§ λ³΄λ©΄ API μ€νμ νλμ νμ ν μ μκ² λμμ΅λλ€.
3. νμ μ λ¬Έμμ΄ λ¦¬ν°λ΄λ‘ ν΅μΌ
λ²λ€λ§ νκ²½μμ μμ μ μΌλ‘ λμνλλ‘ νμ μ λ¬Έμμ΄ λ¦¬ν°λ΄λ‘ ν΅μΌνμ΅λλ€.
// λ³κ²½ μ
@ApiProperty({ type: Number })
price: number;
// λ³κ²½ ν
@ApiProperty({ type: 'number' })
price: number;
// λ°°μ΄μΈ κ²½μ°
@ApiProperty({ type: 'number', isArray: true })
discountRates: number[];
4. nullableκ³Ό optional μ²λ¦¬ λͺ νν
// Optional νλ
@ApiPropertyOptional({ type: 'string' })
@IsOptional()
memo?: string;
// Nullable νλ
@ApiProperty({ type: 'string', nullable: true })
couponCode: string | null;
5. κ³΅ν΅ νμ ν΅μΌ
λͺ¨λ μλΉμ€μμ μ¬μ©νλ header νμ μ ν΅μΌνμ¬ μΌκ΄μ±μ ν보νμ΅λλ€.
// κ³΅ν΅ νμ
μ μ
export const ALL_LANGUAGES = ['ko', 'en', 'ja', 'zh'] as const;
export type Language = typeof ALL_LANGUAGES[number];
// λͺ¨λ μλΉμ€μμ λμΌνκ² μ¬μ©
@ApiSchema()
export class CommonRequestHeader {
@ApiProperty({ enum: ALL_LANGUAGES })
lang: Language;
}
6. κ³΅ν΅ Response λνΌ νμ μ²λ¦¬ κ°μ
λ
Έλ¨Έμ€μμλ λͺ¨λ API μλ΅μ μΌκ΄λ ννλ‘ μ 곡νκΈ° μν΄ FrommResponse<T> κ³΅ν΅ Response λνΌλ₯Ό μ¬μ©νκ³ μμ΅λλ€. νμ§λ§ Swagger λ¬Έμ μμ± μ λ€μκ³Ό κ°μ λ¬Έμ κ° μμμ΅λλ€:
κΈ°μ‘΄ λ¬Έμ :
FrommResponse.dataκ°voidμΈ κ²½μ°μλ Swaggerμ λΉ κ°μ²΄λ‘ νμλ¨FrommResponse.dataκ°nullμΌ μ μλ κ²½μ°required: falseμ€μ μ΄ μ΄λ €μFrommResponse<T>μμTκ° Union νμ μΈ κ²½μ° Swaggerμ oneOf, allOf λ± λ³΅ν© νμ μ²λ¦¬ μ μ½

μ μ΄λ―Έμ§μ²λΌ μλ΅μ data νλκ° Union νμ (oneOf)μΌλ‘ μ¬λ¬ κ°λ₯ν νμ μ κ°μ§λ κ²½μ°, OpenAPI μ€νμμ νμ μ μ ννκ² νννλ κ²μ΄ μ€μν©λλ€.
κ°μ λ°©λ²:
FrommResponse ν΄λμ€μ data νλ μ²λ¦¬λ₯Ό κ°μ νμ΅λλ€.
- void μ²λ¦¬: dataκ° voidμΈ κ²½μ° Swagger μμμ νμλμ§ μλλ‘ μμ
- nullable μ²λ¦¬: dataκ° nullableμΈ κ²½μ°
required: falseλ‘ μ€μ κ°λ₯νλλ‘ μμ - λ³΅ν© νμ μ²λ¦¬: dataκ° Union νμ μΈ κ²½μ° oneOf, allOf λ±μ OpenAPI μ€νμ μ¬λ°λ₯΄κ² μμ±νλλ‘ κ°μ
μ΄λ₯Ό ν΅ν΄ κ° APIμ μλ΅ νμ μ λ§λ μ νν Swagger λ¬Έμκ° μμ±λκ³ , μ¬λ°λ₯Έ νμ μ μ μ μκ² λμμ΅λλ€.
κ²°κ³Ό λ° κ°μ μ¬ν
λ°°ν¬ ν μ μ μλ νμΈ
- DTO ν΄λμ€λͺ μ΄ μλν λλ‘ Swagger UIμ μ¬λ°λ₯΄κ² νμ
- OpenAPI μ€νμμ μμ±λ TypeScript νμ μ΄ μ νν μ΄λ¦μΌλ‘ μμ±λμ΄ νλ‘ νΈμλ νκ³Όμ νμ 곡μ μ±κ³΅
- Request/Response μ€ν€λ§κ° λͺ ννκ² λ λλ§
- λͺ¨λ λ§μ΄ν¬λ‘μλΉμ€μ Swagger λ¬Έμκ° μΌκ΄μ± μκ² κ°μ
κ°λ° κ²½ν κ°μ
- Controller μ½λκ° κ°κ²°ν΄μ Έ κ°λ μ± ν₯μ
- DTOλ§ λ³΄λ©΄ API μ€νμ νλμ νμ κ°λ₯
- κ³΅ν΅ νμ μ¬μ¬μ©μΌλ‘ μ½λ μ€λ³΅ κ°μ
- λͺ μμ νμ μ μλ‘ IDE μλμμ± νμ§ ν₯μ
μ μ§λ³΄μμ± ν₯μ
- DTO λ³κ²½ μ Swagger λ¬Έμ μλ μ λ°μ΄νΈ 보μ₯
- μλ‘μ΄ API μΆκ° μ λμΌν ν¨ν΄μΌλ‘ λΉ λ₯΄κ² μμ± κ°λ₯
- νμ μμ μ± κ°νλ‘ λ°νμ μλ¬ κ°μ
λ§μΉλ©°
μ²μμλ νλ‘ νΈμλμ νμ μ 곡μ νκΈ° μν μ€λΉ κ³Όμ μμ μ°μ°ν λ°κ²¬ν λ¬Έμ μμ§λ§, μ΄λ₯Ό ν΄κ²°νλ κ³Όμ μμ Swagger μ¬μ© ν¨ν΄ μ λ°μ μ κ²νλ©° λ λμ λ°©ν₯μΌλ‘ λ°μ μν¬ μ μμμ΅λλ€. νΉν UIμμΌλ‘λ μμ± λ±μ΄ μ¬λ°λ₯΄κ² 보μ¬μ μ²μμλ μμ차리기 μ΄λ €μ κΈ° λλ¬Έμ, νλ‘ νΈμλ νκ³Όμ νμ μ΄ μμλ€λ©΄ κ³μ λμΉκ³ μμμ λ¬Έμ μμ΅λλ€.
μ΄λ² μμ μ ν΅ν΄ λ°°μ΄ μ μ λ€μκ³Ό κ°μ΅λλ€:
- λ²λ€λ§ νκ²½μ νΉμ± μ΄ν΄: λ²λ€λ¬λ μ½λλ₯Ό μ΅μ ννλ©΄μ ν΄λμ€ λ©νλ°μ΄ν°λ₯Ό λ³κ²½ν μ μμ΅λλ€. λ°°ν¬ νκ²½μμλ§ λ°μνλ μ΄μλ€μ λ°κ²¬νκΈ° μ΄λ €μ°λ―λ‘, λͺ μμ μΈ λ©νλ°μ΄ν° μ§μ μ΄ μ€μν©λλ€.
- μΌκ΄λ νμ μ μ ν¨ν΄: λ§μ΄ν¬λ‘μλΉμ€ νκ²½μμλ λͺ¨λ μλΉμ€κ° λμΌν ν¨ν΄μ λ°λ₯Ό λ μ 체 μλΉμ€μ νμ§μ ν¨κ³Όμ μΌλ‘ λμΌ μ μμ΅λλ€.
- DTO μ€μ¬μ API λ¬Έμν: Controllerμ ν©μ΄μ§ λ©νλ°μ΄ν°λ₯Ό DTOλ‘ ν΅ν©νλ©΄, API μ€νμ νλμ νμ ν μ μκ³ μ μ§λ³΄μμ±μ΄ ν¬κ² ν₯μλ©λλ€.
- ν κ° νμ μ μ€μμ±: νλ‘ νΈμλ νκ³Όμ νμ 곡μ μμ μ΄ μμλ€λ©΄ λ°κ²¬νμ§ λͺ»νμ λ¬Έμ μμ΅λλ€. μλ‘ λ€λ₯Έ κ΄μ μμ λ°λΌλ³΄λ κ²μ΄ νμ§ ν₯μμ λμμ΄ λ©λλ€.
μλ²λ¦¬μ€ νκ²½μμ Swaggerλ₯Ό μ¬μ©νλ©° λΉμ·ν κ³ λ―Όμ νμλ λΆλ€κ» μ΄ κΈμ΄ λμμ΄ λμμΌλ©΄ μ’κ² μ΅λλ€.
μ½μ΄μ£Όμ μ κ°μ¬ν©λλ€.