티스토리 뷰

기타

Spring REST Docs

SonSeungWoo 2019. 10. 2. 16:59

Spring REST Docs는 정확하고 읽기 쉬운 RESTful 서비스에 대한 문서를 생성합니다. 손으로 작성한 문서와 Spring 테스트로 생성 된 자동 생성 문서 snippets(스니펫)을 결합해서 사용 할 수 있게 해줍니다.

자바 문서 자동화에는 Spring REST Docs 이외에 대표적으로 Swagger가 있습니다. 필자는 Swagger의 경험만 있었다...문서 자동화라는 공통점이 있지만 각각 용도,목적??은 다르다.

 

  Spring REST Docs Swagger
용도 문서 제공용 API 테스트를 위한 용도에 더 집중됨
장점 깔금하고 API 명세에 집중

적용하기 상대적으로 쉬움

API 테스트 UI제공

단점

Test코드 기반 문서 작성됨 (Test코드 필수)

설정등 적용하기 어려움

코드에 어노테이션 추가해야한다.

코드와 문서 동기화 안될 수있다.

이제 간단한 예제를 만들어 보자. 필자는 intellij, maven, spring boot 2.1.8, jpa 기반으로 프로젝트를 만들었다. 그리고 아래와 같이 pom.xml에아래와 같이 dependency를 추가해주자. Spring REST docs의 기본 조합은 Mock Mvc & Asciidoc 문법이다.

 

Spring MVC 테스트 지원을 사용하여 테스트를 작성하므로 spring-restdocs-mockmvc를 아래와 같이 추가해 주자.

WebTestClient 또는 REST Assured를 사용하여 테스트를 작성하려면 spring-restdocs-webtestclient 및 spring-restdocs-restassured 를 dependency를 추가 해야하지만 여기선 하지 않겠다.

	<dependency>
		<groupId>org.springframework.restdocs</groupId>
		<artifactId>spring-restdocs-mockmvc</artifactId>
		<scope>test</scope>
	</dependency>

 

asciidoctor 플러그인을 추가합니다. 그리고 spring-restdocs-asciidoctor를 dependency를 추가합니다. 문서 자동 생성 snippets가 자동으로 구성됩니다. 자세한 설명은 여기에 있습니다.

            <plugin>
                <groupId>org.asciidoctor</groupId>
                <artifactId>asciidoctor-maven-plugin</artifactId>
                <version>1.5.7</version>
                <executions>
                    <execution>
                        <id>generate-docs</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>process-asciidoc</goal>
                        </goals>
                        <configuration>
                            <backend>html</backend>
                            <doctype>book</doctype>
                        </configuration>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.springframework.restdocs</groupId>
                        <artifactId>spring-restdocs-asciidoctor</artifactId>
                        <version>${spring-restdocs.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

 

asciidoctor 설정으로 outputDirectory 문서가 출력되는 디렉토리 경로 입니다. 

            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.7</version>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>
                                ${project.build.outputDirectory}/static/docs
                            </outputDirectory>
                            <resources>
                                <resource>
                                    <directory>
                                        ${project.build.directory}/generated-docs
                                    </directory>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

 

Spring MVC Test 프레임 워크를 사용하여 문서화 할 REST 서비스에 대한 요청을 작성합니다. 테스트를 실행하면 요청 및 결과 응답에 대한 문서가 생성됩니다. JUnit 4 및 JUnit 5 라이브러리를 사용할 수 있습니다. 필자는 JUnit 5 로 진행하겠다.

 

아래와 같이 dependency를 추가합니다.

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit-jupiter-engine}</version>
            <scope>test</scope>
        </dependency>

 

JUnit 5 테스트로 작업하려면 RestDocumentationExtension 클래스를 사용하여 테스트를 해야합니다. 이 클래스는 Maven을 사용할 때 / target / generated-snippets 출력 디렉토리 또는 Gradle에 / build / generate-snippets를 사용하여 자동으로 구성됩니다.

 

기본 CRUD API가(controller, repository, domain등등) 작업되어 있다는 가정하에 진행하겠다. 이제 테스트를 작성해 보자. RestDocumentationResultHandler 설정에 {class-name}/{method-name}은 generated-snippets아래에 클래스명/메소드명 경로가 생성되고 그아래 *.adoc파일 들이 생성된다.

@ExtendWith({RestDocumentationExtension.class, SpringExtension.class})
@SpringBootTest
public class PersonControllerTest {

    private MockMvc mockMvc;

    private RestDocumentationResultHandler document;

    @BeforeEach
    public void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
        this.document = document(
                "{class-name}/{method-name}",
                preprocessRequest(prettyPrint()),
                preprocessResponse(prettyPrint())
        );
        this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                .apply(documentationConfiguration(restDocumentation))
                .alwaysDo(document)
                .build();
    }
}

 

필자는 person 전체조회와 name 으로 한건만 조회하는 테스트케이스를 작성했다.

    @Test
    public void getPersonList() throws Exception {
        this.mockMvc.perform(get("/person")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andDo(document.document(
                        responseFields(
                                fieldWithPath("[].id").description("The id of the output"),
                                fieldWithPath("[].name").description("The name of the output"),
                                fieldWithPath("[].email").description("The email of the output"),
                                fieldWithPath("[].date").description("The date of the output"))));
    }

    @Test
    public void getPerson() throws Exception {
        this.mockMvc.perform(get("/person/{name}", "seungwoo")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andDo(document.document(
                        pathParameters(parameterWithName("name").description("PathVariable name")),
                        /*requestFields(
                                fieldWithPath("name").description("The name of the input")),*/
                        responseFields(
                                fieldWithPath("id").description("The id of the output"),
                                fieldWithPath("name").description("The name of the output"),
                                fieldWithPath("email").description("The email of the output"),
                                fieldWithPath("date").description("The date of the output"))))
                .andExpect(jsonPath("$.id", is(notNullValue())))
                .andExpect(jsonPath("$.name", is(notNullValue())))
                .andExpect(jsonPath("$.email", is(notNullValue())))
                .andExpect(jsonPath("$.date", is(notNullValue())));
    }

위코드에서 예로 responseFields는 응답 fields 정보이다. 자세히는 설명하지 않겠다. 딱 보면 다들 알거라고 생각한다.

테스트를 실행하고 잘된다면 mvn clean install를 실행하자. target/generated-snippets에 {class-name}/{method-name} 명으로 위코드로 봤을땐 person-controller-test/get-person 이런식으로 폴더가 생성되며 그아래 *.adoc 파일들이 생성된다.

 

일단 위 테스트와 파일이 잘 생성 되었다면 이제 html파일을 생성하도록 작업을 하자. src/main/asciidoc/api-guide.adoc 라는 파일을 만들자. 필자기준 이므로 파일명은 편한대로 하면 될 듯하다.

파일 내용은 아래와 같다. asciidoc 문법이다. 더 자세한건 여기를 참고하자.

= REST Service API Guide
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 4
:sectlinks:

= Resources

== Person REST Service

The Person provides the entry point into the service.

=== Accessing the person GET with provided content

==== Request structure

== 사용자 리스트 조회 [get]

사용자리스트 조회


include::{snippets}/person-controller-test/get-person-list/curl-request.adoc[]

=== 요청 구조

include::{snippets}/person-controller-test/get-person-list/http-request.adoc[]

==== 요청 파라미터들

include::{snippets}/person-controller-test/get-person-list/request-parameters.adoc[]

=== 응답 구조

include::{snippets}/person-controller-test/get-person-list/http-response.adoc[]

==== 응답 파라미터들

include::{snippets}/person-controller-test/get-person-list/response-fields.adoc[]

== 사용자 조회 [get]

사용자 조회


include::{snippets}/person-controller-test/get-person/curl-request.adoc[]

=== 요청 구조

include::{snippets}/person-controller-test/get-person/http-request.adoc[]

==== 요청 파라미터들

include::{snippets}/person-controller-test/get-person/path-parameters.adoc[]

=== 응답 구조

include::{snippets}/person-controller-test/get-person/http-response.adoc[]

==== 응답 파라미터들

include::{snippets}/person-controller-test/get-person/response-fields.adoc[]

 

다시 mvn clean install를 실행하면 target/generated-docs 아래에 api-guide.html파일이 생성된다. api-guide,html을 브러우저에서 실행하면 아래와 같이 문서가 보일것이다.

 

 

요청 파라미터를 커스터마이징 하고싶다면 src/test/resources/org/springframework/restdocs/templates 경로에

request-fields.snippet 파일을 추가하면 된다. 문법은 mustache이다.

===== Request Fields
|===
|필드명|타입|설명|필수값|Byte

{{#fields}}

|{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}}
|{{#tableCellContent}}`+{{type}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}
|{{#tableCellContent}}{{^optional}}true{{/optional}}{{/tableCellContent}}
|{{#tableCellContent}}{{#byte}}{{.}}{{/byte}}{{/tableCellContent}}

{{/fields}}

|===

 

아래와 같이 문서가 작성된다.

 

간단한 Spring REST docs 예제는 github에 있다.

'기타' 카테고리의 다른 글

Apache Kafka  (0) 2019.06.28
Mybatis oracle procedure xmlType 처리  (0) 2019.02.15
maven multi 모듈  (0) 2019.01.26
Agile Practices - Scrum/Kanban  (0) 2018.04.23
TDD, BDD  (0) 2018.04.23
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2024/12   »
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
글 보관함