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문서.
여러가지 세팅법이 있고 사전에 준비해야 하는 것들이 많이 있지만,
사용하지 않을 것이기 때문에 본문에서는 다루지 않는다.
@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
방식을 아예 포기할 생각은 아니다.
시간이 있다면 더 알아 보고 해결방법이 있다며 다시 갈아 타고 싶다.
그 만큼 매리트가 있다고 생각했다.
하지만 지금은 사용하기 많이 애매하고 힘들다고 생각한다.