스프링

[스프링] Swagger에서 multipart/formdata형식으로 json, image동시에 보내기

Ash_jisu 2025. 4. 23. 23:33

문제 발생 배경

Mutlipart form 형식 필요와 문제

  • image를 보내야하는경우 Multipart 요청을 보내야함
  • 근데 이제 request json과 image를 동시에 받아야하는경우 문제가 발생
  • mutlipart에서 applicaton/json으로 Content-Type지정이 필요

Swagger UI의 한계

  • Postman에서는 Content Type지정이 가능
  • Swagger UI에서는 각 파트별로 Content-Type을 명시적으로 설정 불가능
  • 기본설정이 application/octet-stream 이다

오류 발생

  • 서버에서는 application/octet-stream을 처리할 수 없다는 HttpMediaTypeNotSupportedException(415 UNSUPPORTED_MEDIA_TYPE) 오류가 발생

 


해결 시도 및 방법

기본적으로 2가지 방법이 존재합니다. 본인은 1번 선택

1 . SwaggerBody 커스텀 어노테이션(springdoc-openapi 2.3 버전 출시에 따른 사용가능)

  • 목적: Swagger 문서에서 multipart 요청의 JSON 데이터 파트에 대해 올바른 encoding 정보를 추가하여,Swagger UI에서 "Try it out" 시 해당 파트의 Content-Type을 application/json으로 지정함
  • 적용 대상:
    • JSON 데이터와 파일을 동시에 보내는 API 
    • Swagger UI 내에서 JSON 파트의 Content-Type이 올바르게 설정되지 않는 문제 해결

2. MultipartJackson2HttpMessageConverter 도입

  • 목적: 클라이언트(또는 Swagger UI)에서 JSON 파트가 잘못된 Content-Type(기본값: application/octet-stream)으로 전송되어도 서버가 이를 변환하려고 시도하지 않도록 하여, 415 오류를 우회하는 해결책
  • 동작 원리:
    • AbstractJackson2HttpMessageConverter를 상속하여,
    • application/octet-stream Content-Type에 대해 변환이 시도되지 않도록 오버라이딩
  • 주의사항: 이 방법은 근본적으로 클라이언트에서 올바른 Content-Type(application/json)을 설정하도록 하는 것이 최선이나, Swagger UI 테스트나 임시 환경에서는 잘못된 Content-Type으로 인한 문제를 회피할 수 있는 우회책으로 사용

 


코드 적용 및 결과

코드 적용

Gradle

  • 주의사항: springdoc 버전 2.3이상으로 사용!!!
    // swagger
    implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'

 

SwaggerBody

  • 어노테이션 대신 별도 생성 이유: 어노테이션으로 하면 Swagger의 어노테이션 RequestBody와 Spring controller의 RequestBody 어노테이션이랑 겹침, 따라서 명을 변경해줘야함, custom interface 생성
package com.example.lettering.util;

import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;

/*
 * 생성 이유: Swagger에서 Mutipart formdata 형식 업로드 가능하게 하기 위한 Custom Swagger Body
 * 순서: Swagger의 RequestBody를 사용해야지만 가능 -> Controller에서 Spring의 RequestBody이름과 겹침 따라서 별도의 Custom 생성 후 이름 변경 필요
 * */

@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@RequestBody
public @interface SwaggerBody {

    @AliasFor(annotation = RequestBody.class)
    String description() default "";

    @AliasFor(annotation = RequestBody.class)
    Content[] content() default {};

    @AliasFor(annotation = RequestBody.class)
    boolean required() default false;

    @AliasFor(annotation = RequestBody.class)
    Extension[] extensions() default {};

    @AliasFor(annotation = RequestBody.class)
    String ref() default "";
}

 

 

Controller API 일부 작성

  • Swagger Custom RequestBody인 SwaggerBody 언급
  @Operation(summary = "실링왁스 등록 기능", description = "실링왁스 디자인을 추가합니다.")
    @SwaggerBody(content = @Content(encoding = @Encoding(name = "sealingwax", contentType = MediaType.APPLICATION_JSON_VALUE)))
    @PostMapping(value = "/backoffice", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<SealingWaxResponse> createSealingWax(
            @RequestPart("sealingwax") CreateSealingWaxRequest createSealingWaxRequest,
            @RequestPart("image") MultipartFile imageFile) throws IOException {
        return ResponseEntity.ok(sealingWaxService.createSealingWax(createSealingWaxRequest, imageFile));
    }

 

결과

  • type= applicaton/json 잘 적용된 모습

 

 


출처

2.3 · Releases · springdoc/springdoc-openapi

 

Releases · springdoc/springdoc-openapi

Library for OpenAPI 3 with spring-boot. Contribute to springdoc/springdoc-openapi development by creating an account on GitHub.

github.com

 

 

Swagger(스웨거) multipart/form-data에서 try out이 불가능한 문제 "Content-Type 'application/octet-stream' is not supported"

 

Swagger(스웨거) multipart/form-data에서 try out이 불가능한 문제 "Content-Type 'application/octet-stream' is not supp

개요 평소 API 문서 자동화 프레임워크로 `Swagger`를 많이 써왔는데 `multipart/form-data`를 Body로 받는 API의 경우 `Swagger` 문서에서 try out(실행)할 시에 예외(HttpMediaTypeNotSupportedException)가 발생하는 문제

aahc912.tistory.com