본문 바로가기
Spring

[Spring REST Docs] 맛보기

by hseong 2023. 3. 23.

프로젝트에 스웨거를 추가해서 사용해보니 영 마음에 들지 않는다.

 

Spring REST Docs

Document RESTful services by combining hand-written documentation with auto-generated snippets produced with Spring MVC Test or WebTestClient.

docs.spring.io

spring initializr에서 spring rest docs 종속성만 추가했을때 오류가 발생하여 공식 문서를 참조하였다.

 

실습을 위해 간단한 컨트롤러와 테스트 코드를 작성한다.

@RestController
@RequiredArgsConstructor
public class MemberController {

    private final MemberService memberService;

    @PostMapping("/members")
    @ResponseStatus(value = HttpStatus.CREATED)
    public Result<Long> hello(MemberCreateRequest request) {
        Long memberId = memberService.createMember(request);

        return new Result<>("201", memberId);
    }

    @GetMapping("/members")
    public Result<List<Member>> getMembers() {
        List<Member> members = memberService.getMembers();

        return new Result<>("200", members);
    }

    @GetMapping("/members/{memberId}")
    public Result<Member> getMember(@PathVariable("memberId") Long memberId) {
        Member member = memberService.getMember(memberId);

        return new Result<>("200", member);
    }

    @PatchMapping("/members/{memberId}")
    public Result<Long> updateMember(@PathVariable Long memberId, MemberUpdateRequest request) {
        Long responseMemberId = memberService.updateMember(memberId, request);

        return new Result<>("200", responseMemberId);
    }
}
@WebMvcTest(MemberController.class)
@AutoConfigureRestDocs
class MemberControllerTest {

    @Autowired
    MockMvc mvc;

    @Autowired
    ObjectMapper mapper;

    @MockBean
    MemberService memberService;
    
    @Test
    public void getMembers() throws Exception {
        //given
        MemberCreateRequest request = new MemberCreateRequest();
        request.setName("member");
        request.setAge(10);
        request.setNickname("member");

        Member member = Member.create(request);

        given(memberService.getMembers()).willReturn(List.of(member));

        //when
        ResultActions result = mvc.perform(get("/members")
                .accept(MediaType.APPLICATION_JSON));

        //then
        result.andExpect(status().isOk())
                .andDo(print())
                .andDo(document("members-get",
                        preprocessRequest(prettyPrint()),
                        preprocessResponse(prettyPrint()),
                        responseFields(
                                fieldWithPath("code").type(JsonFieldType.STRING).description("응답코드"),
                                fieldWithPath("data").type(JsonFieldType.ARRAY).description("회원 리스트"),
                                fieldWithPath("data[].id").type(JsonFieldType.NUMBER).description("회원 id"),
                                fieldWithPath("data[].name").type(JsonFieldType.STRING).description("이름"),
                                fieldWithPath("data[].age").type(JsonFieldType.NUMBER).description("나이"),
                                fieldWithPath("data[].nickname").type(JsonFieldType.STRING).description("닉네임")
                                )
                        )
                );
    }
    
    @Test
    public void updateMember() throws Exception {
        //given
        MemberUpdateRequest request = new MemberUpdateRequest();
        request.setName("member");
        request.setAge(10);
        request.setNickname("member");

        given(memberService.updateMember(any(), any())).willReturn(1L);

        //when
        ResultActions result = mvc.perform(patch("/members/{memberId}", 1L)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(mapper.writeValueAsString(request))
                        .accept(MediaType.APPLICATION_JSON));

        //then
        result.andExpect(status().isOk())
                .andDo(print())
                .andDo(document("members-update-one",
                                preprocessRequest(
                                        prettyPrint()
                                ),
                                preprocessResponse(prettyPrint()),
                                pathParameters(
                                        parameterWithName("memberId").description("회원 id")
                                ),
                                requestFields(
                                        fieldWithPath("name").type(JsonFieldType.STRING).description("이름"),
                                        fieldWithPath("age").type(JsonFieldType.NUMBER).description("나이"),
                                        fieldWithPath("nickname").type(JsonFieldType.STRING).description("닉네임")
                                ),
                                responseFields(
                                        fieldWithPath("code").type(JsonFieldType.STRING).description("응답코드"),
                                        fieldWithPath("data").type(JsonFieldType.NUMBER).description("회원 id")
                                )
                        )
                );

    }
}
  • pathParameters
    • parameterWithName("key의 명칭").description("key에 대한 설명")
  • requestFields
  • responseFields
    • fieldWithPath("key 값").type(value의 타입).dscription("value에 대한 설명")

테스트 통과 후 build/generated_snippets 아래에 지정한 이름에 따른 문서들이 생성된다.

src/docs/asciidoc 아래에 index.adoc 파일을 생성하고 아래와 같이 작성한다.

operation은 스니펫들을 한꺼번에 추가하고, include는 개별 스니펫을 지정가능하다.


빌드 후 build/docs/asciidoc 아래에 index.html 파일이 생성된다.

 

 참고: https://techblog.woowahan.com/2597/