Spring RestDocs 작성 가이드 #1 기본편
Github: https://github.com/syakuis/spring-restdocs
Spring RestDocs 는 RestController 의 REST API 에 대해 테스트 코드를 작성한 것을 토대로 자동으로 API 문서를 생성할 수 있는 라이브러리이다.
개발 사양
- Spring boot 2.4.5
- Spring RestDocs 2.0.5
- Asciidoctor
설정
Gradle 기반으로 작성되었습니다.
build.gradle
buildscript {
ext.restDocsVersion = "2.0.5.RELEASE"
dependencies {
classpath "org.asciidoctor:asciidoctor-gradle-plugin:1.5.3"
}
}
apply plugin: "org.asciidoctor.convert"
dependencies {
asciidoctor "org.springframework.restdocs:spring-restdocs-asciidoctor:${restDocsVersion}"
testImplementation "org.springframework.restdocs:spring-restdocs-mockmvc:${restDocsVersion}"
}
def snippetsDir = file("${buildDir}/generated-snippets")
asciidoctor {
attributes "snippets": snippetsDir
inputs.dir snippetsDir
dependsOn test
}
asciidoctor.doFirst {
delete file('src/main/resources/static/docs')
}
task copyAsciidoc(type: Copy) {
dependsOn asciidoctor
from file("${buildDir}/asciidoc/html5")
into file("src/main/resources/static/docs")
}
test {
outputs.dir snippetsDir
}
build {
dependsOn copyAsciidoc
}
bootJar {
dependsOn copyAsciidoc
from ("${asciidoctor.outputDir}/html5") {
into "BOOT-INF/classes/static/docs"
}
}
순차적으로 작업에 대해 설명하겠습니다.
- buildscript > asciidoctor gradle plugin 을 추가한다.
- apply plugin > asciidoctor gradle plugin 을 활성화 한다.
- dependencies > spring restdocs 라이브러리를 추가한다.
- asciidoctor 작업에 대해 정의한다.
- test 작업이 실행될때 asciidoctor 작업도 실행한다.
- asciidoctor.doFirst > asciidoctor 작업이 실행되기 전에 실행한다.
- copyAsciidoc 작업을 직접 만들었다.
- build 작업이 실행될때 asciidoctor 작업도 실행한다.
- bootJar 작업이 실행될때 asciidoctor 작업도 실행한다.
- restdocs 문서 파일을 jar 배포 파일에 포함될 수 있도록 한다.
Gradle 작업에 대한 설명
- asciidoctor: 테스트 코드를 기반으로 Asciidoctor 파일을 생성합니다.
- copyAsciidoc: 생성된 Asciidoctor 파일을 웹 서비스에서 제공할 수 있도록 복사합니다.
- http://localhost:8080/docs/index.html 로 열람할 수 있습니다.
템플릿이 되는 Asciidoc 용 index.aboc 생성하기
src/docs/asciidoc/index.adoc 파일을 생성하고 아래와 같이 합니다. (예시 입니다.)
ifndef::snippets[]
:snippets: ../../../build/generated-snippets
endif::[]
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 4
:sectlinks:
:site-url: /build/asciidoc/html5/
= 제목
****
WARNING: 경고....
****
[[introduction]]
== 소개
[[introduction]]
== 서비스 환경
|===
| 환경 | URI
| 개발
| <http://127.0.0.1:5000>
| 운영
| <http://localhost:5000>
|===
ifndef::snippet[]
:snippet: ../../../build/generated-snippets
endif::[]
필요한 내용은 직접 작성하면 됩니다.
구현
테스트 코드만 가이드하였고 서비스 로직을 가진 구현체는 생략하였습니다.
Configuration
Spring RestDocs 공통 설정을 구현한다. test 패키지에 생성합니다.
@Configuration
public class RestDocsTestConfiguration {
@Bean
public RestDocsMockMvcConfigurationCustomizer restDocsMockMvcConfigurationCustomizer() {
return configurer -> configurer.operationPreprocessors()
.withRequestDefaults(prettyPrint())
.withResponseDefaults(prettyPrint());
}
}
Unit Test
@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs
class SignupRestControllerTest {
@Autowired
private MockMvc mvc;
@Autowired
private ObjectMapper objectMapper;
@Test
void signup() throws Exception {
AccountRequestDto.Signup request = AccountRequestDto.Signup.builder()
.name("read")
.username("man")
.password("VlHv4")
.build();
mvc.perform(post("/accounts/v1/users/signup")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isCreated())
.andDo(document("accounts/v1/users/signup",
requestHeaders(
headerWithName(HttpHeaders.CONTENT_TYPE).description(MediaType.APPLICATION_JSON),
headerWithName(HttpHeaders.ACCEPT).description(MediaType.APPLICATION_JSON)
),
requestFields(
fieldWithPath("username").description("사용자 이름"),
fieldWithPath("password").description("암호"),
fieldWithPath("name").description("이름")
),
responseFields(
fieldWithPath("id").description("번호"),
fieldWithPath("username").description("사용자 이름"),
fieldWithPath("name").description("이름"),
fieldWithPath("disabled").description("비활성"),
fieldWithPath("blocked").description("잠금"),
fieldWithPath("uid").description("사용자 아이디"),
fieldWithPath("updatedOn").description("수정일"),
fieldWithPath("registeredOn").description("생성일")
)
));
}
}
문서 생성 및 추가 작업
- Gradle asciidoctor 작업을 실행합니다.
- build/generated-snippets/accounts/v1/signup 폴더에 adoc 파일이 생성됩니다.
- 하이라이트된 경로는 테스트 코드에서 설정한 경로입니다. 아래 코드에 해당합니다.
- .andDo(document("accounts/v1/users/signup",
- 하이라이트된 경로는 테스트 코드에서 설정한 경로입니다. 아래 코드에 해당합니다.
- requestHeaders() : 요청 헤더를 설정합니다.
- requestFields(): 요청 Body 필드를 설정합니다.
- responseFields(): 응답 Body 필드를 설정합니다.
- 추가적으로
- pathParameters(): 요청 url 에 대한 경로를 설정합니다.
- requestParameters(): 요청 파라메터를 설정합니다.
pathParameters 를 사용할 경우
MockHttpServletRequestBuilder 대신 RestDocumentationRequestBuilders 를 사용해야 합니다.
Response Body 가 배열인 경우
FieldDescriptor[] accountFields = Arrays.asList(
fieldWithPath("id").description("번호"),
fieldWithPath("username").description("사용자 이름"),
fieldWithPath("name").description("이름"),
fieldWithPath("disabled").description("비활성"),
fieldWithPath("blocked").description("잠금"),
fieldWithPath("uid").description("사용자 아이디"),
fieldWithPath("updatedOn").description("수정일"),
fieldWithPath("registeredOn").description("생성일")
);
// 아래와 같이 사용해야 합니다.
responseFields(fieldWithPath("[]").description("계정 목록"))
.andWithPrefix("[].", accountFields)
템플릿이 되는 Asciidoc 용 index.aboc 에 생성된 adoc 파일 추가하기
맨하단에 추가하면 됩니다.
== 사용자
=== 회원 가입
**Request**
include::{snippet}/accounts/v1/users/signup/http-request.adoc[]
**Request Header**
include::{snippet}/accounts/v1/users/signup/request-headers.adoc[]
**Request Body**
include::{snippet}/accounts/v1/users/signup/request-fields.adoc[]
**Response**
include::{snippet}/accounts/v1/users/signup/http-response.adoc[]
**Response Body**
include::{snippet}/accounts/v1/users/signup/response-fields.adoc[]
끝
다음 Spring RestDocs 가이드에는 중복되는 코드들을 제거하고 문서 관리 효율적일 수 있는 방법을 제공하겠습니다.
참고링크
'Tech' 카테고리의 다른 글
QueryDSL for Spring Data JPA (0) | 2021.10.06 |
---|---|
Spring RestDocs 작성 가이드 #2 응용편 - 보일러플레이트 코드 제거 (0) | 2021.09.14 |
Spring MVC Test - Response Body 한글 깨짐 이슈 (0) | 2021.09.12 |
도커로 테스트 환경 구성하기 - Docker, Test Containers (0) | 2021.09.12 |