포스트

Rest docs + swagger문서 작성(@modelattribute, @requestpart 대응 문제)

RestDocs + Swagger란?

  • RestDocs와 같이 테스트 코드를 이용하여 API문서를 작성할 수 있다.
  • RestDocs의 단점인 시각적으로 불편하고 직접 API를 문서에서 테스트할 수 없는 점을 SwaggerUi를 사용해서 개선할 수 있다.


epages. OpenAPI Specification(OAS)

  • restful API 문서의 표준 규약
  • SwaggerUi는 OAS를 API 스펙으로 시각화 해준다.


RestDocs-api-spec

  • RestDocs Wrapper Class를 이용해 테스트 코드를 작성하면 OAS를 만들어 준다.


즉, RestDocs Wrapper Class를 이용해서 OAS를 만들고 SwaggerUi를 이용해서 API문서를 시각화 해준다.




문제점


사용하면서 테스트를 반자동화하여 문서를 작성할 수 있다는게 편하면서도 재미있다고 느꼈다.
하지만 사용하면서 한계를 느끼고 폐기하기로 했다… 작성해 놓은 것들이 아깝지만 어쩔 수 없는 선택이라고 생각한다.
대충 작성법을 보자면 아래와 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    @Test
    @DisplayName("email로 회원 찾기 성공")
    void findMember() throws Exception {

        // given
        Member member = createMember(email, role);

        JwtDto jwt = jwtDto();


        // expected
        mockMvc.perform(RestDocumentationRequestBuilders.get("/member/find/{email}", member.getEmail())
                        .contentType(MediaType.APPLICATION_JSON)
                        .header(HttpHeaders.AUTHORIZATION, jwtDto().getGrantType()+" "+jwt.getAccessToken()))
                .andExpect(status().isOk())
                .andDo(print())
                .andDo(MockMvcRestDocumentationWrapper.document("회원 찾기 성공",
                                resourceDetails().description("회원 찾기"),
                                preprocessRequest(prettyPrint()),
                                preprocessResponse(prettyPrint()),
                                requestHeaders(headerWithName(HttpHeaders.AUTHORIZATION).description("Bearer 토큰").getAttributes()),
                                responseFields(
                                        fieldWithPath("id").type(JsonFieldType.NUMBER).description("ID"),
                                        fieldWithPath("email").type(JsonFieldType.STRING).description("이메일"),
                                        fieldWithPath("name").type(JsonFieldType.STRING).description("이름")
                                )
                        )

                );

    }


해당 테스트 코드로 작성된 Swagger문서.


swagger

여러가지 세팅법이 있고 사전에 준비해야 하는 것들이 많이 있지만,
사용하지 않을 것이기 때문에 본문에서는 다루지 않는다.


@RequestPart, @ModelAttribute 문제


roomPost의 글을 작성할 때 MultipartFile를 사용하여 이미지를 업로드 한다.
이미지 뿐만이 아니라 글작성에 필요한 request도 @ModelAttribute를 통해서 받는다.


1
2
3
4
5
6
7
8
    @PostMapping(value = "/create")
    public ResponseEntity roomPostCreate(@Valid @ModelAttribute RoomPostRequest roomPostRequest,
                                            @RequestPart(value = "uploadImages") List<MultipartFile> uploadImages){

        roomPostService.createRoom(roomPostRequest, uploadImages);

        return ResponseEntity.status(HttpStatus.OK).build();
    }


문제의 원인이 된 Controller.
@ModelAttribute@RequestParts를 문서에 작성하기 위해서 아무리 찾아 보고 시도해봐도 답이 나오지 않았다.


Spring Rest Docs 문서
https://docs.spring.io/spring-restdocs/docs/current/reference/htmlsingle/#documenting-your-api-request-parts-payloads-fields


해당 문서를 보면

1
2
3
4
5
6
7
8
MockMultipartFile image = new MockMultipartFile("image", "image.png", "image/png", "<<png data>>".getBytes());
MockMultipartFile metadata = new MockMultipartFile("metadata", "", "application/json",
		"{ \"version\": \"1.0\"}".getBytes());

this.mockMvc.perform(multipart("/images").file(image).file(metadata).accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("image-upload", requestPartFields("metadata", 
			fieldWithPath("version").description("The version of the image")))); 


requestPartFields를 사용하여 MockMultipartFile을 문서화 할 수 있다고 나와 있지만, RestDosc만 가능하고 실제로 SwaggerUi를 이용해서 문서를 작성하려고 하면
테스트를 통과 하더라도


테스트 성공


위와 같이 필드를 만들 수가 없다…

1
2
3
4
requestParameters( 
        parameterWithName("title").description("제목"),
        parameterWithName("name").description("이름")
),


requestParameters를 사용해서 param으로 받아온 값들을 문서에 만들 수 있다고 하는데 이것 또한 MockMvcRestDocumentationWrapper를 사용하여 만든다면 컴파일 조차 불가능하다…


더군다나 공식문서가 존재하지도 않으며, https://github.com/ePages-de/restdocs-api-spec 해당 repository의 README의 정보도 세팅과 간단한 시연정도 뿐이었다.


그렇게 계속 많은 시도를 해보고 찾아보아도 확실한 해결법이 나오지 않아서 지금 사용하기는 부적합하다고 판단했다.
OpenAPI의 버전을 2로 낮추면 위에서 언급했던 requestParameters를 사용할 수 있지만, 역시 requestParts는 문서에 적용이 되지 않는다.




해결


결국 Swagger를 사용하기로 하고 controller의 테스트는 그대로 꼼곰히 작성하며 Swagger 어노테이션을 항상 검수하기로 했다..

RestDocs는 문서로써 너무 보기에 불편하고 테스트를 직접 해볼 수 없기때문에 적합하지 않다고 생각했다.


해결이라고 보기는 애매하지만 이번에 어떤 점이 불편하고 어떤 점이 힘든지 확실히 알게 되었다.
그렇다고 RestDocs + Swagger방식을 아예 포기할 생각은 아니다.
시간이 있다면 더 알아 보고 해결방법이 있다며 다시 갈아 타고 싶다.

그 만큼 매리트가 있다고 생각했다.
하지만 지금은 사용하기 많이 애매하고 힘들다고 생각한다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.