티스토리 뷰

Back-End/Spring

Spring REST Docs 란?

wan-blog 2020. 6. 1. 03:22
반응형

Spring REST Docs 란?

프로젝트를 하다 보면 같이 협업하는 사람들에게 API 문서를 제공할 일이 많습니다. 그런데 직접 API를 위키나 문서에 정리하게 되면 코드와의 싱크를 맞추기가 정말 힘듭니다. 대부분 API 코드가 변경되면 문서를 잘 변경하지 않습니다. API의 문서에 존재도 모르는 경우도 많습니다. 이러한 문제를 해결해 주는 게 Spring REST Docs입니다.

Spring REST Docs는 test code 기반으로 아래와 같이 문서를 생성해 줍니다. Test code 기반으로 문서가 생성되기 때문에 코드가 변경 되더라도 코드 기반으로 문서를 자동으로 업데이트하기 때문에 코드와 문서에 싱크 문제도 존재하지 않습니다. 이러한 이유로 Rest docs는 API 문서로 사용하는데 아주 좋습니다. 이번 글에서는 테스트 코드만으로도 API 문서를 생성해 주는Spring REST Docs에 사용방법에 대해 정리해보겠습니다.

https://i.imgur.com/1Xyqoeq.png

Spring Rest docs를 설정하기 위해서는 크게 3가지를 설정해야합니다. build.gradle, Spring REST Docs Test Code 작성, adoc 작성 입니다.

Build gradle 설정하기

plugins { //1
    id 'org.springframework.boot' version '2.3.0.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'org.asciidoctor.convert' version '1.5.3'
    id 'java'
}

dependencies {

    asciidoctor 'org.springframework.restdocs:spring-restdocs-asciidoctor' //2
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' //3
}

ext { //4
    snippetsDir = "${buildDir}/generated-snippets"
}

test { //5
    outputs.dir snippetsDir
    useJUnitPlatform()
}

asciidoctor { //6
    inputs.dir snippetsDir//7
    dependsOn test // 8
}

bootJar {
    dependsOn asciidoctor // 9
    from("${asciidoctor.outputDir}/html5") {// 10 
        into 'static/docs'
    }
}
  1. Asciidoctor plugin
  2. asciidoctor 구성에 spring-restdocs-asciidoctor디펜던시를 추가한다. 이것은 자동적으로 나의 프로젝트에서 .adoc파일들을 읽어 build/generated-snippets 에 파일읽어 HTML문서로 export한다. 빌드툴마다 경로가다른데 경로는 아래와같다.

Spring REST Docs asciidoctor

Build tool Source files Generated files
Maven src/main/asciidoc/*.adoc target/generated-docs/*.html
Gradle src/docs/asciidoc/*.adoc build/asciidoc/html5/*.html

Spring REST Docs-asciidoctor

  1. Spring mvc 기반에 snippets을 뽑고싶다면 해당 의존성을 추가해주면된다.

  2. snippets의 생성될 위치를 지정해주면된다.

  3. 테스트 테스크가 실행될때 snippets들이 생성위치에 떨어지게 설정해준다.

  4. asciidoctor 테스크를 구성한다.

  5. 입력 snippets이 생성될 위치를 지정해준다.

  6. 문서가 만들어지기전에 test가 실행되도록 의존성을 걸어준다.

  7. jar 생성전에 asciidoctor 테스크가 실행되도록 설정해준다.

  8. jar static 폴더에 rest docs가 HTML로 생성되면 넣어준다.

Spring REST Docs Test code 작성

아래는 멤버를 조회하는 평범한 Controller 코드 입니다.

@RestController
@RequestMapping("/api/members")
@RequiredArgsConstructor
public class MemberController {

    private final MemberService memberService;

    @GetMapping("/{id}")
    public Member getMember(@PathVariable Long id){
        return memberService.getMember(id);
    }
}

아래는 controller 단위 테스트와 resdocs를 생성하도록 test code를 작성한 예제 코드입니다. 관련 설명은 주석을 작성했습니다.

@ExtendWith({RestDocumentationExtension.class, SpringExtension.class})
@WebMvcTest(MemberController.class)
class MemberControllerTest {

    protected MockMvc mockMvc;

    @MockBean
    private MemberService memberService;

    @BeforeEach
    void setUp(WebApplicationContext webApplicationContext,
            RestDocumentationContextProvider restDocumentation) { // MVC rest docs setting
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                .apply(documentationConfiguration(restDocumentation)
                .operationPreprocessors()
                .withRequestDefaults(prettyPrint()) // requset 값 정렬
                .withResponseDefaults(prettyPrint())) // response 값 정렬        
                                .build();
    }

    @Test
    void getMember() throws Exception {

        given(memberService.getMember(ArgumentMatchers.anyLong())).willReturn(new Member(1L, "wan"));

        //when
        //then
        mockMvc.perform(RestDocumentationRequestBuilders.get("/api/members/{id}", 12345))
            .andDo(print())
            .andDo( // request, response fields 문서 작성
                document("member",
                    pathParameters(
                        parameterWithName("id").description("회원 ID")
                    ),
                    responseFields(getDescription("id", "회원 ID"),
                            getDescription("name", "회원 이름")
                    ))
            ).andExpect(status().isOk());

    }

    private FieldDescriptor getDescription(String name, String description) {
        return PayloadDocumentation.fieldWithPath(name)
                .description(description);
    }
}

크게 신경써야할부분은 2가지입니다.

  1. MVC rest docs 셋팅
  2. request, response fields 문서 작성

ADOC 작성

workspace/src/docs/asciidoc에 index.adoc을 작성합니다.

= Member API
:doctype: book
:toc: left
:sectnums:
:toclevels: 3
:source-highlighter: highlightjs

== Host
|===
|환경|Host
|LOCAL|http://localhost:8080
|===

== APIs
URL은 `/api/`로 시작한다.

include::member.adoc[]

workspace/src/docs/asciidoc에 member.adoc을 작성합니다.

=== Member

==== GET
===== Request
Request 형식은 다음과 같다:
include::{snippets}/member/http-request.adoc[]

include::{snippets}/member/path-parameters.adoc[]

====== Try with curl
include::{snippets}/member/curl-request.adoc[]

===== Response
성공할 경우 response 형식은 다음과 같다:
include::{snippets}/member/http-response.adoc[]

====== Response Fields
include::{snippets}/member/response-fields.adoc[]

그런다음 아래와같이 빌드를 하고 jar를 실행한 후 http://localhost:8080/docs/index.html 접속해보면 완성된 REST Dcos를 확인하실 수 있습니다.

$ ./gradlew build
$ java -jar build/libs/demo-0.0.1-SNAPSHOT.jar

관련 깃허브 소스입니다.

참고

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함