먼저 스프링 프로젝트를 생성합니다. https://start.spring.io 에서 아래와 같이 Spring Web, Lombok 의존성을 추가하여 생성합니다.
이번 예제에서는 API만 구현하므로 데이터베이스 관련 의존성은 추가하지 않았습니다.
build.gradle 파일에 Spring REST Docs 의존성을 추가합니다. 아래 주석의 1 ~ 8번 까지의 내용을 추가합니다.
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.4'
id 'io.spring.dependency-management' version '1.1.3'
id 'org.asciidoctor.jvm.convert' version '3.3.2' // (1)
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
asciidoctorExt // (2)
}
repositories {
mavenCentral()
}
// (3)
ext {
set('snippetsDir', file("build/generated-snippets"))
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' // (4)
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' // (5)
}
tasks.named('test') {
outputs.dir snippetsDir // (6)
useJUnitPlatform()
}
// (7)
tasks.named('asciidoctor') {
inputs.dir snippetsDir
configurations 'asciidoctorExt'
sources{
include("**/index.adoc")
}
baseDirFollowsSourceFile()
dependsOn test
}
// (8)
bootJar {
dependsOn asciidoctor
from("${asciidoctor.outputDir}") {
into 'static/docs'
}
}
static/docs
경로에 API 명세서 문서가 포함됩니다.게시글 생성, 조회, 업데이트, 삭제 API를 작성해보겠습니다.
먼저 API 공통 응답 포맷을 사용하기 위해 아래와 같이 CommonResponse 제네릭 클래스를 작성합니다.
게시글 목록 조회, 게시글 조회, 게시글 생성, 게시글 업데이트, 게시글 삭제 API를 아래와 같이 작성합니다.
PostService 클래스에는 비즈니스 로직을 작성합니다. 저는 일단 null만 리턴하도록 구현하였습니다. 테스트시에는 Mock 객체를 삽입할 것이기 때문입니다.
먼저 아래와 같이 docs
패키지를 생성합니다.
RestDocsTest 클래스를 작성합니다. 이 클래스는 추상 클래스로 템플릿 메서드 패턴을 사용하여 initializeController
메서드를 하위 클래스에서 구현하도록 합니다.
다음으로 docs/post
패키지를 생성하고 RestDocsTest
클래스를 상속 받는 PostControllerDocsTest 클래스를 작성합니다. PostService Mock 객체를 생성하고, initializeController
메서드를 아래와 같이 구현합니다.
게시글 목록 조회 API 테스트 코드입니다.
게시글 조회 API 테스트 코드입니다.
게시글 생성 API 테스트 코드입니다.
게시글 업데이트 API 테스트 코드입니다.
게시글 삭제 API 테스트 코드입니다.
src
밑에 docs/index.adoc
파일을 생성합니다.
index.adoc
파일은 API 문서 자동 생성시 index.html
파일로 변환되어 jar 파일에 포함됩니다. 아래와 같이 작성합니다.
index.adoc
파일에는 API 문서의 전체 구조를 정의합니다. 그리고 다른 adoc 파일을 incldue
명령어를 사용하여 삽입할 수 있습니다. 아래에서는 api/post/post.adoc
파일을 삽입하였습니다.
ifndef::snippets[]
:snippets: ../../build/generated-snippets
endif::[]
= API 명세서
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 2
:sectlinks:
= Common
== 공통 API 응답 포맷
== 응답 상태 코드 및 메세지
= API
== Post API
include::api/post/post.adoc[]
이어서 docs/api/post/post.adoc
파일을 생성합니다. 이 파일에는 게시글 생성, 조회, 업데이트, 삭제 API를 작성합니다. 전체적인 구조만 작성하고, 실제 내용은 자동 생성된 adoc
파일 들을 include
명령어를 통해 삽입합니다.
=== 게시글 목록 조회 API
==== 1. Curl Request
include::{snippets}/get-posts/curl-request.adoc[]
==== 2. HTTP Request
include::{snippets}/get-posts/http-request.adoc[]
==== 3. HTTP Request Headers
// include::{snippets}/get-posts/request-headers.adoc[]
==== 4. HTTP Request Parameters
===== 1) Path Parameters
// include::{snippets}/get-posts/path-parameters.adoc[]
===== 2) Query Parameters
include::{snippets}/get-posts/query-parameters.adoc[]
===== 3) Form Parameters
// include::{snippets}/get-posts/form-parameters.adoc[]
==== 5. HTTP Request Body
include::{snippets}/get-posts/request-body.adoc[]
// include::{snippets}/get-posts/request-fields.adoc[]
==== 6. HTTP Response Body
include::{snippets}/get-posts/response-body.adoc[]
include::{snippets}/get-posts/response-fields.adoc[]
=== 게시글 조회 API
==== 1. Curl Request
include::{snippets}/get-post/curl-request.adoc[]
==== 2. HTTP Request
include::{snippets}/get-post/http-request.adoc[]
==== 3. HTTP Request Headers
// include::{snippets}/get-post/request-headers.adoc[]
==== 4. HTTP Request Parameters
===== 1) Path Parameters
include::{snippets}/get-post/path-parameters.adoc[]
===== 2) Query Parameters
// include::{snippets}/get-post/query-parameters.adoc[]
===== 3) Form Parameters
// include::{snippets}/get-post/form-parameters.adoc[]
==== 5. HTTP Request Body
include::{snippets}/get-post/request-body.adoc[]
// include::{snippets}/get-post/request-fields.adoc[]
==== 6. HTTP Response Body
include::{snippets}/get-post/response-body.adoc[]
include::{snippets}/get-post/response-fields.adoc[]
=== 게시글 생성 API
==== 1. Curl Request
include::{snippets}/create-posts/curl-request.adoc[]
==== 2. HTTP Request
include::{snippets}/create-posts/http-request.adoc[]
==== 3. HTTP Request Headers
include::{snippets}/create-posts/request-headers.adoc[]
==== 4. HTTP Request Parameters
===== 1) Path Parameters
//include::{snippets}/create-posts/path-parameters.adoc[]
===== 2) Query Parameters
//include::{snippets}/create-posts/query-parameters.adoc[]
===== 3) Form Parameters
// include::{snippets}/create-posts/form-parameters.adoc[]
==== 5. HTTP Request Body
include::{snippets}/create-posts/request-body.adoc[]
// include::{snippets}/create-posts/request-fields.adoc[]
==== 6. HTTP Response Body
include::{snippets}/create-posts/response-body.adoc[]
include::{snippets}/create-posts/response-fields.adoc[]
=== 게시글 업데이트 API
==== 1. Curl Request
include::{snippets}/update-posts/curl-request.adoc[]
==== 2. HTTP Request
include::{snippets}/update-posts/http-request.adoc[]
==== 3. HTTP Request Headers
include::{snippets}/update-posts/request-headers.adoc[]
==== 4. HTTP Request Parameters
===== 1) Path Parameters
include::{snippets}/update-posts/path-parameters.adoc[]
===== 2) Query Parameters
// include::{snippets}/update-posts/query-parameters.adoc[]
===== 3) Form Parameters
// include::{snippets}/update-posts/form-parameters.adoc[]
==== 5. HTTP Request Body
include::{snippets}/update-posts/request-body.adoc[]
include::{snippets}/update-posts/request-fields.adoc[]
==== 6. HTTP Response Body
include::{snippets}/update-posts/response-body.adoc[]
include::{snippets}/update-posts/response-fields.adoc[]
=== 게시글 삭제 API
==== 1. Curl Request
include::{snippets}/delete-posts/curl-request.adoc[]
==== 2. HTTP Request
include::{snippets}/delete-posts/http-request.adoc[]
==== 3. HTTP Request Headers
include::{snippets}/delete-posts/request-headers.adoc[]
==== 4. HTTP Request Parameters
===== 1) Path Parameters
include::{snippets}/delete-posts/path-parameters.adoc[]
===== 2) Query Parameters
// include::{snippets}/delete-posts/query-parameters.adoc[]
===== 3) Form Parameters
// include::{snippets}/delete-posts/form-parameters.adoc[]
==== 5. HTTP Request Body
include::{snippets}/delete-posts/request-body.adoc[]
// include::{snippets}/delete-posts/request-fields.adoc[]
==== 6. HTTP Response Body
include::{snippets}/delete-posts/response-body.adoc[]
include::{snippets}/delete-posts/response-fields.adoc[]
위에서 작성한 API 문서에서 각 API에 삽입할 adoc
문서 들을 테스트 코드를 기반으로 자동 생성합니다.
당연히 테스트 코드가 통과되어야 문서가 생성됩니다.
터미널에서 Gradle의 bootJar
태스크를 실행합니다.
./gradlew bootJar
태스크 실행이 성공하면, build/generated-snippets
디렉토리 하위에 위의 테스트 코드에서 document
메서드에 전달하는 파라미터 값으로 디렉토리가 생성됩니다.
해당 디렉토리에는 테스트 코드를 기반으로 adoc
확장자의 문서가 생성됩니다.
각각의 문서에는 CURL 명령어, HTTP 요청, HTTP 응답, HTTP 헤더, 파라미터, 바디 등의 정보가 테스트 코드에서 작성한 내용을 기반으로 생성됩니다.
bootJar
태스크로 생성된 jar 파일에 API 문서가 포함됩니다. 따라서 애플리케이션을 먼저 실행합니다.
java -jar build/libs/restdocs-0.0.1-SNAPSHOT.jar
http://localhost:8080/docs/index.html 경로로 접속하면 API 문서가 출력됩니다.
전체 코드는 https://github.com/nefertirii/restdocs 에서 확인하실 수 있습니다.