Backend/SpringBoot

json과 파일 데이터 동시에 받기(ft. Postman, swagger 에서 테스트)

Dean83 2025. 9. 18. 14:04

API 구성을 하다보면, 보통 파일을 올리는 API가 따로 있고, json을 받는 API가 따로 있게 되긴 하는데, 같이 보낼 경우도 있다. 

이럴 경우 content-type 가 multipart/form-data 로 들어 오게 된다. 

 

이걸 다루기 이전에, 파일을 서버가 받는 방식부터 알아보면, 

  • multipart/form-data 로 받아서 MultipartFile 형으로 받는 방식이 있다
  • base64 인코딩을 통해 json으로 받는다. 

일반적으로 MultipartFile 을 통해 받는것이 선호된다. 그 이유는, 

  • 메세지의 용량이 json으로 주는것 보다 작다
  • 사용하기 편리하다
  • 디코딩 과정이 없으므로 속도 및 부하가 적어 대용량에서도 잘 쓰는 방식이다. 

간단히 컨트롤러의 매핑된 메소드 예를 보면, 

...

@PostMapping(value="/create")
public User createUser(@RequestPart UserCreateRequest request, @RequestPart(required = false) MultipartFile profileCreateRequest) {
    return userService.create(request, Optional.ofNullable(profileCreateRequest));
}

...

이렇게 @RequestPart를 이용해서 MultipartFile 로 받는다. 

일반 json과 파일형식을 multipart/form-data 로 받게 되면 위의 예 처럼 json 또한 @RequestPart 로 받아야 한다. 

 

API에서 요청 인자값을 받는 몇가지 방식에 대해 알아보자. 

  • @RequestParam
    • GET 요청에서, 파라메터 형식으로 받을때 (?id=xxxx)
    • multipart/form-data 에서 일반 text로 받는 경우 사용
      • 그러나 대부분은 dto를 이용하므로 이런경우는 잘 없음
  • @RequestPart
    • multipart/form-data 에서 json 이나 file 을 받을때 사용
  • @PathVariable
    • API 주소 뒤 /에 인자값이 추가된 경우.
@GetMapping("/users/{userId}")
public User getUser(@PathVariable("userId") String userId) {
    // userId == "123"
    return userService.findById(userId);
}

 

 

  • PostMan 을 이용한 테스트
    • 주로 포스트맨을 이용해서 API 통신 테스트를 하게된다

  • Body -> form-data 를 선택
  • Json 추가
    • Key 에 이름을 입력(서버에서 받는 변수명과 일치하는게 좋음) -> 형식은 Text로 지정
    • Value 에 json 문자열 자체를 입력
    • Content-Type 에 application/json 을 명시 꼭 해야 함
      • 이 항목이 없다면 우측에 있는 Bulk Edit 좌측 ... 눌러서 추가
  • 파일 추가
    • Key 에 이름 입력(서버에서 받는 변수명과 일치하는게 좋음) -> 형식은 File 로 지정
    • Value 에서 보낼 파일을 선택

 

Swagger의 문제점 -> 서버 코드 수정

위의 방식대로 하면 포스트맨에선 아무 문제 없다. 다만, Swagger에서는 문제가 생긴다. Swagger 에서는 application/json 과 multipart/form-data 를 같이 쓸 수가 없다. 따라서 json 문자열과 파일을 같이 보내면 

Content-Type 'application/octet-stream' is not supported 오류가 발생하게 된다.

 

이를 해결하기 위한 방법으론, 

1.  json 을 "파일" 로 보낸다

  • json 내용을 파일로 작성하여, 파일을 추가 후 보낸다. 

2. json을 text로 보낸 후 서버 내부에서 파싱한다

 

2번 방식으로 접근하면, 포스트맨에서도, swagger 에서도 모두 동작한다. 다만 HttpMessageConverter 가 json을 DTO 클래스로 Deserialize를 할 수 없으므로, 컨트롤러 코드 내부에서 수동으로 작업을 해주어야 한다.

 

...

@PostMapping(value="/create")
public User createUser(@RequestPart String request, @RequestPart(required = false) MultipartFile profileCreateRequest) {
    
    //아래의 코드를 사용하여 수동으로 Deserialize를 해야 한다.
    DTO클래스명 변수명 = new ObjectMapper().readValue(request, DTO클래스명.class);
    
    return userService.create(변수명, Optional.ofNullable(profileCreateRequest));
}

...

 

 

이때, 포스트맨에서는 json 문자열을 전송할때, Content-type 설정을 기존 application/json 에서 application/text 로 변경한다