Spring REST Docs 란?
Spring REST Docs 란?
프로젝트를 하다 보면 같이 협업하는 사람들에게 API 문서를 제공할 일이 많습니다. 그런데 직접 API를 위키나 문서에 정리하게 되면 코드와의 싱크를 맞추기가 정말 힘듭니다. 대부분 API 코드가 변경되면 문서를 잘 변경하지 않습니다. API의 문서에 존재도 모르는 경우도 많습니다. 이러한 문제를 해결해 주는 게 Spring REST Docs입니다.
Spring REST Docs는 test code 기반으로 아래와 같이 문서를 생성해 줍니다. Test code 기반으로 문서가 생성되기 때문에 코드가 변경 되더라도 코드 기반으로 문서를 자동으로 업데이트하기 때문에 코드와 문서에 싱크 문제도 존재하지 않습니다. 이러한 이유로 Rest docs는 API 문서로 사용하는데 아주 좋습니다. 이번 글에서는 테스트 코드만으로도 API 문서를 생성해 주는Spring REST Docs에 사용방법에 대해 정리해보겠습니다.
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'
}
}
- Asciidoctor plugin
- 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 mvc 기반에 snippets을 뽑고싶다면 해당 의존성을 추가해주면된다.
snippets의 생성될 위치를 지정해주면된다.
테스트 테스크가 실행될때 snippets들이 생성위치에 떨어지게 설정해준다.
asciidoctor 테스크를 구성한다.
입력 snippets이 생성될 위치를 지정해준다.
문서가 만들어지기전에 test가 실행되도록 의존성을 걸어준다.
jar 생성전에 asciidoctor 테스크가 실행되도록 설정해준다.
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가지입니다.
- MVC rest docs 셋팅
- 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
관련 깃허브 소스입니다.
참고