Swagger "Unable to render this definition error"

선종우·2023년 9월 4일
0

오답노트

목록 보기
4/5

1. 문제상황

  • 신규 프로젝트를 진행하며 Swagger를 적용하였다.
    • 프로젝트 세팅은 다른 개발자분이 진행해주셨다.
  • 서버를 올리고 swagger 화면으로 접속하니 아래와 같은 응답이 출력됐다.
  • http://localhost:8080/v3/api-docs 경로로 접속하니 아래와 같은 응답이 출력됐다.
  • 보아하니 base64url encoding인 것 같아 decoding해보니 json응답값이 나왔다.
  • swagger ui는 이 api-docs가 정상적인 json형태가 나와야 파싱이 되는 듯 하다.
  • 그러나 세팅한 분께 물어봐도 정확히 왜 이런 증상이 나는지 알지는 못하셨다.

2. 디버깅

  • 디버깅을 해보니 swagger ui에 접근할 때 openapiJson메소드를 호출했다. 메소드의 반환값은 byte[]였다. 이게 아마 api-docs가 출력한 base64url로 인코딩된 값인 듯 했다.
  • 더 추적해보니 HttpMessageConverter가 정상적으로 응답을 변환해주지 못하는 듯했다.
  • 기본적으로 Byte array는 ByteArrayHttpMessageConverter가 변환을 수행해야 하나, 문제 상황에서는 MappingJackson2HttpMessageConverter가 변환을 수행하고 있었다.

3. 문제 원인

  • 문제 원인은 수동 등록한 MessageConverter때문이었다.
  • configureMessageConverters주석을 보면 아래와 같은 주석이 달려있다.

    Note that use of this method turns off default converter
    registration

  • 실제로 해당 설정때문에 MessageConverter가 2개만 등록이 되어있었다.
  • 그렇다보니 openapiJson의 응답값을 처리할 converter를 처리하는 과정에서 MappingJackson2HttpMessageConverter가 처리를 담당하게 되었고, 정상적은 변환이 이뤄지지 않은 것이다.

4. 해결책

  • Spring은 Default MessageConverter를 유지하면서 MessageConverter를 수정하기 위한 메소드 extendMessageConverters를 추가 제공한다.

  • 메소드에 대한 설명은 아래와 같다.

    Extend or modify the list of converters after it has been, either configured or initialized with a default list.
    Note that the order of converter registration is important. Especially in cases where clients accept org.springframework.http.MediaType.ALL the converters configured earlier will be preferred.

  • 스프링이 제공하는 Default Converter리스트는 아래와 같다.

    0 = {ByteArrayHttpMessageConverter}
    1 = {StringHttpMessageConverter}
    2 = {ResourceHttpMessageConverter}
    3 = {ResourceRegionHttpMessageConverter}
    4 = {AllEncompassingFormHttpMessageConverter}
    5 = {Jaxb2RootElementHttpMessageConverter}
    6 = {MappingJackson2HttpMessageConverter}
  • 위 리스트 순서를 고려해 적절하게 MessageConverter를 삽입, 수정, 삭제하면 된다.
  • 예시
    override fun extendMessageConverters(converters: MutableList<HttpMessageConverter<*>>) {
        //(converters[1] as? StringHttpMessageConverter)?.defaultCharset = StandardCharsets.UTF_8
        //StringMessageConverter 기본 charset 변경
        if (converters[1] is HttpMessageConverter) {
            (converters[1] as StringHttpMessageConverter).defaultCharset = StandardCharsets.UTF_8
        }
        //kotlin data class나 lazyloding 기존 jackson mapper를 사용하면 문제가 생긴다고 한다.
        //기존 MappingJackson2HttpMessageConverter앞에 Kotlin용 Mapper 추가
        converters.add(6, MappingJackson2HttpMessageConverter(Jackson.mapper()))
    }
  • SpringBoot방식으로는 Reference이 있다.
    • 주의할 점은 프로젝트 내에 @EnableWebMvc코드가 있으면 autoconfig설정이 적용되지 않아 Converter빈이 정상등록되질 않는다.

0개의 댓글