BE/Spring & Spring Boot

[Spring Boot] REST Docs + Asciidoctor

baek-dev 2025. 2. 15. 09:31

Spring Boot에서 REST DocsAsciidoctor를 사용하면 API 명세서를 자동으로 생성할 수 있음.

이는 테스트 코드 기반으로 문서를 생성하기 때문에, 코드와 문서가 항상 일치하도록 유지할 수 있음.

📌 1. REST Docs + Asciidoctor란?

🔹 Spring REST Docs

API 문서를 자동으로 생성할 수 있도록 지원하는 라이브러리

API 응답을 테스트하며, 이를 기반으로 문서를 생성함

문서와 실제 동작하는 코드의 일관성 유지 가능

 

🔹 Asciidoctor

AsciiDoc 문법을 사용하여 문서를 작성하는 도구

마크다운(Markdown)과 비슷하지만 기능이 더 강력

HTML, PDF, ePub 등의 다양한 형식으로 변환 가능

 

✅ 왜 REST Docs를 사용해야 할까?

비교 Swagger REST Docs
문서 작성 방식 수동 (Controller에 Annotation 추가) 자동 (테스트 코드 기반)
코드 일관성 유지하기 어려움 유지하기 쉬움
UI 제공 제공 (Swagger UI) 제공 안 됨 (별도 HTML 변환 필요)
강력한 문서 기능 보통 Asciidoctor로 강력한 문서 지원

 

📌 2. 프로젝트 설정 (Gradle 기준)

build.gradle에 다음을 추가해야 함.

plugins {
    id 'org.asciidoctor.jvm.convert' version '3.3.2'
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.restdocs:spring-restdocs-restassured'
}

tasks.named('test') {
    useJUnitPlatform()
    outputs.dir snippetsDir
}

tasks.named('asciidoctor') {
    inputs.dir snippetsDir
    dependsOn test
}

ext {
    snippetsDir = file('build/generated-snippets')
}

 

📌 3. REST Docs 테스트 코드 작성

✅ Controller 만들기

@RestController
@RequestMapping("/api/users")
public class UserController {

    @GetMapping("/{id}")
    public ResponseEntity<UserResponse> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(new UserResponse(id, "홍길동", "hong@example.com"));
    }
}

 

✅ 테스트 코드 작성

Spring REST Docs는 테스트 코드 기반으로 문서를 생성하기 때문에, MockMvc를 활용하여 API를 호출하고, 결과를 기록해야 함.

@WebMvcTest(UserController.class)
@AutoConfigureRestDocs(outputDir = "build/generated-snippets")
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void getUserTest() throws Exception {
        mockMvc.perform(get("/api/users/{id}", 1L)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andDo(document("get-user",
                        pathParameters(
                                parameterWithName("id").description("사용자 ID")
                        ),
                        responseFields(
                                fieldWithPath("id").description("사용자 ID"),
                                fieldWithPath("name").description("사용자 이름"),
                                fieldWithPath("email").description("사용자 이메일")
                        )
                ));
    }
}

 

🔹 설명

1. @AutoConfigureRestDocs

outputDir = "build/generated-snippets" → 문서가 저장될 경로 지정

 

2. mockMvc.perform(get("/api/users/{id}", 1L))

MockMvc를 사용하여 API 호출

 

3. document("get-user", ...)

"get-user"라는 API 문서 조각(snippet) 생성

pathParameters(...) → 요청 변수 설명

responseFields(...) → 응답 필드 설명

 

📌 4. Asciidoc 파일 생성

테스트가 실행되면 build/generated-snippets/get-user에 **API 문서 조각(snippet)**이 생성됨.

이를 .adoc 파일에 포함하여 전체 문서를 만든다.

 

📁 src/docs/asciidoc/index.adoc

= User API 문서
:toc: left
:toc-title: 목차
:sectlinks:

== 사용자 조회 API

=== 요청

include::{snippets}/get-user/http-request.adoc[]

=== 응답

include::{snippets}/get-user/http-response.adoc[]

 

📌 5. API 문서를 HTML로 변환

✅ Gradle로 변환 실행

./gradlew asciidoctor

build/docs/asciidoc/index.html 파일이 생성됨 → 브라우저에서 열어볼 수 있음

 

✅ Spring Boot에서 자동으로 문서 제공

📁 src/main/resources/application.properties

spring.mvc.static-path-pattern=/docs/**
spring.resources.static-locations=file:build/docs/asciidoc/

 

이렇게 설정하면, http://localhost:8080/docs/index.html에서 API 문서를 확인할 수 있음.

 

📌 6. 최종 정리

단계 설명
1. Gradle 설정 REST Docs + Asciidoctor 의존성 추가
2. 테스트 코드 작성 MockMvc로 API 테스트 & 문서 생성 (document())
3. AsciiDoc 작성 .adoc 파일을 생성하고 snippets 포함
4. HTML 변환 ./gradlew asciidoctor 실행 후 문서 확인

 

 

🚀 결론

REST Docs + Asciidoctor를 사용하면 테스트 코드 기반의 API 문서를 자동으로 생성할 수 있음.

API와 문서를 동기화할 필요가 없음 (테스트 코드가 문서를 생성하기 때문)

문서가 더 정확하고 신뢰할 수 있음 (테스트가 실패하면 문서도 갱신됨)

Swagger보다 더 강력한 문서 표현이 가능 (AsciiDoc을 활용)

 

 

 

 

출처 : ChatGPT