Spring-Rest-Docs
- 테스트 코드를 기반으로 Restful API 문서 작성을 돕는 도구
- Asciidoctor를 사용하여 HTML 등 다양한 포맷으로 문서를 자동 출력할 수 있다.
- API Spec과 문서화를 위한 테스트 코드가 일치하지 않으면, 테스트 빌드를 실패하게 되어 테스트 코드로 검증된 문서임을 보장할 수 있다.
Swagger
- @ApiOperation 등 코드에는 영향을 주지 않지만, Swagger를 위해서 지속적으로 추가 코드를 작성해야 한다.
- 명세를 위한 코드들이 너무 많아 가독성이 떨어질 수 있다.
- 구조가 변경되었을 때, 명세도 같이 변경하지 않으면 초기 명세와 달라질 가능성이 존재한다.
프로젝트를 진행하면서, API 문서 자동화를 위해 Swagger와 Spring-Rest-Docs 중 고민하다 위와 같은 이유로 Spring-Rest-Docs를 선택하였다.
실습
환경: SpringBoot 2.7.5
1. build.gradle 세팅
plugins {
id 'org.asciidoctor.jvm.convert' version '3.3.2'
}
configurations {
asciidoctorExtensions
}
ext {
set('snippetsDir', file("build/generated-snippets"))
}
dependencies {
asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor'
testImplementation 'org.springframework.restdocs:spring-restdocs-webtestclient'
}
test {
outputs.dir snippetsDir
}
asciidoctor {
inputs.dir snippetsDir
sources {
include '**/api-docs.adoc'
}
configurations 'asciidoctorExtensions'
dependsOn test
baseDirFollowsSourceFile()
}
task copyDocument(type: Copy) {
dependsOn asciidoctor
from file("build/docs/asciidoc")
into file("src/main/resources/static/docs")
}
bootJar {
dependsOn copyDocument
}
- 기존 build.gradle에 위와 같은 코드를 추가한다.
- 테스트 코드 실행 및 성공 시, snippetsDir로 설정한 경로에 아래와 같은 .adoc파일이 생성된다.
- curl-request.adoc
- http-request.adoc
- http-response.adoc
- httpie-request.adoc
- request-body.adoc
- response-body.adoc
- 프로젝트 build 시, asciidoctor 과정이 실행되어 src/docs/asciidoc 경로의 api-docs.adoc을 기반으로 html 파일을 /build/docs/asciidoc 경로에 생성한다.
- copyDocument 과정에서 생성된 html을 src/main/resources/static/docs로 복사한다.
2. 테스트 코드 작성
@ExtendWith(RestDocumentationExtension.class)
class ControllerTest {
@BeforeEach
void setUp(ApplicationContext applicationContext, RestDocumentationContextProvider restDocumentation) {
this.webTestClient = WebTestClient.bindToApplicationContext(applicationContext).configureClient()
.filter(documentationConfiguration(restDocumentation))
.build();
}
@Test
@DisplayName("테스트")
void 테스트() throws Exception {
// given
User testUser = TestProvider.createTestUser();
LinkedMultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.put("email", List.of(testUser.getEmail()));
formData.put("password", List.of(testUser.getPassword()));
formData.put("name", List.of(testUser.getName()));
formData.put("nickname", List.of(testUser.getNickname()));
formData.put("age", List.of(testUser.getAge().toString()));
formData.put("gender", List.of(testUser.getGender()));
// when & then
webTestClient.post()
.uri("/api/v1/auth/sign-up")
.body(BodyInserters.fromFormData(formData))
.exchange()
.expectStatus().isCreated()
.expectBody()
.jsonPath("code").isEqualTo(201)
.consumeWith(document("snippets 생성 경로", requestParameters(
parameterWithName("email").description("이메일").attributes(field("example", testUser.getEmail()), field("length", "0-20")),
parameterWithName("password").description("비밀번호").attributes(field("example", testUser.getPassword()), field("length", "10-15")),
parameterWithName("name").description("이름").attributes(field("example", testUser.getName())),
parameterWithName("nickname").description("닉네임").attributes(field("example", testUser.getNickname())),
parameterWithName("age").description("나이").attributes(field("example", String.valueOf(testUser.getAge()))),
parameterWithName("gender").description("성별").attributes(field("example", testUser.getGender()))
)))
.consumeWith(System.out::println);
}
}
- @ExtendWith(RestDocumentationExtension.class)를 테스트 클래스에 적용한다.
- setUp 메서드를 사용하여, WebTestClient에 Rest-Docs를 사용할 수 있도록 적용한다.
- document()를 사용해서 설정한 내용을 바탕으로 .adoc 파일을 snippets 생성 경로에 생성한다.
- build/generated-snippets/{지정한 경로}에 위와 같은 .adoc 파일이 생성된 것을 확인할 수 있다.
3. api-docs.adoc 파일 작성
operation::{파일 경로}[snippets='http-request,request-parameters,response-body']
- build/generated-snippets 아래의 파일 경로를 적용한 뒤, 위에서 생성된 .adoc 파일 중 사용하고 싶은 파일을 snippets=''에 작성한다.
- AsciiDoc 플러그인을 사용하면, 다음과 같은 파일 결과를 미리 볼 수 있다.
4. project build
- 터미널에 ./gradlew clean build 명령어를 입력한 뒤, resources/static/docs/api-docs.html 파일을 확인하면 다음과 같은 결과를 확인할 수 있다.
'Backend > Spring' 카테고리의 다른 글
[Spring] checkstyle 적용하기 (0) | 2023.05.03 |
---|---|
DDD(Domain Driven Design)란? (1) | 2023.04.03 |
[Spring] 알림 기능에 SSE 적용하기 (0) | 2022.11.25 |
[Spring] Logback 설정 (0) | 2022.11.16 |
[Slf4j] Slf4j란? (0) | 2022.09.19 |