UploadImages: (
    apiOperationOptions: Required<Pick<Partial<OperationObject>, 'summary'>> &
      Partial<OperationObject>,
  ): PropertyDecorator => {
    return applyDecorators(
      ApiOperation(apiOperationOptions),
      **ApiConsumes('multipart/form-data'),
      ApiBody({
        schema: {
          type: 'object',
          properties: {
            eventImages: {
              type: 'array',
              items: {
                type: 'string',
                format: 'binary',
              },
            },
            data: {
              $ref: '#/components/schemas/CreateEventDto',
            },
          },
        },**
      }),
    );

Untitled

이미지를 사용하는 api에서 스웨거를 작성하려면 위 코드에서 강조한 부분처럼 작성해야한다.

만약 이런 코드가 여러곳이라면 코드의 중복도 많고 보기에 상당히 복잡할 것이다. 이를 스웨거빌더로 따로 만들어 간단하게 작성할 수 있도록 하겠다.

전체 코드

export class MultipartFormDataRequestDto {
  static swaggerBuilder(
    key: string,
    imageKey: string,
    type: Type,
    options: Omit<ApiPropertyOptions, 'name' | 'type'> = {},
  ) {
    class Temp extends this {
      @ApiProperty({
        name: imageKey,
        type: 'string',
        format: 'binary',
        ...options,
      })
      private readonly image: string;

      @ApiProperty({
        name: 'data',
        type,
      })
      private readonly data: string;
    }

    Object.defineProperty(Temp, 'name', {
      value: `${key}RequestDto`,
    });

    return applyDecorators(
      ApiConsumes('multipart/form-data'),
      ApiBody({
        type: Temp,
      }),
    );
  }
}

임시 클래스를 만들고 프로퍼티를 정의해준다.

해당 프로퍼티의 정보는 모두 ApiProperty에 선언한 대로 나오기 때문에 이부분을 커스텀해준다.

프로퍼티명은 name을 통해서 정의된다. 이를 파라미터로 받은 imageKey로 할당받게해준다.

이후 format을 통해 binary로 만들어준다. 이를 통해 텍스트가 아닌 파일형태도 받을 수 있게 한다.

class Temp extends this {
  @ApiProperty({
    name: imageKey,
    type: 'string',
    format: 'binary',
    ...options,
  })
  private readonly image: string;

이후 바디로 파싱할 데이터는 data라는 객체로 할당하게 할 것이다. 이때의 type은 요청때 Body에 걸 DTO를 사용하도록 한다.

 @ApiProperty({
    name: 'data',
    type,
  })
  private readonly data: string;

스웨거는 할당된 클래스명를 통해서 자신의 스키마를 정의하게된다. 만약 Object.defineProperty를 통해 임시 클래스를 정의해두지 않으면 ApiBody에 할당된 Temp의 클래스명 Temp가 그대로 할당된다. 만약 다른 API 스웨거에서도 MultipartFormDataRequestDto를 통해 스웨거를 등록하면 서로 중복되어 스웨거에서 값이 같아지는 불상사가 일어나게된다.

  Object.defineProperty(Temp, 'name', {
      value: `${key}RequestDto`,
    });
    
  return applyDecorators(
  ApiConsumes('multipart/form-data'),
  ApiBody({
    type: Temp,
  }),
);
}