티스토리 뷰
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 |