關注點
- Spring REST Docs 服務的啟動,生成 API 文件,並將文件部署到網頁上供外部訪問。
Spring REST Docs
什麼是 Spring REST Docs?
Spring REST Docs 是由 Spring 官方提供且維護的工具,
結合了測試驅動開發(TDD)的理念,透過執行測試來自動生成準確的 RESTful API 文件,確保程式碼與文件始終保持同步。
加入相關依賴
- junit-jupiter: 提供 JUnit 5 的核心測試功能,支持撰寫與執行單元測試和整合測試。
- spring-test: 提供對 Spring 應用程式的測試支援,包括模擬 Web 環境、測試上下文管理等。
- spring-restdocs-mockmvc: Spring REST Docs 的 MockMvc 模組,允許在測試中截獲 API 請求與回應的細節,並生成 API 文件片段 (snippets)。
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>6.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>7.0.5</version> <scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<version>3.0.1</version> <scope>test</scope>
</dependency>
加入 Asciidoctor 套件
- asciidoctor-maven-plugin: 將 AsciiDoc 文件轉換為 HTML、PDF 等格式的功能,支持在 Maven 建置過程中自動生成文件。
- spring-restdocs-asciidoctor: 提供與 Asciidoctor 套件整合的功能,讓產生的片段能以 AsciiDoc 格式進行排版。
<properties>
<snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
</properties>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>generate-docs</id>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html</backend>
<doctype>book</doctype>
<attributes>
<snippets>${snippetsDirectory}</snippets>
</attributes>
<sourceDirectory>src/main/asciidoc</sourceDirectory>
<outputDirectory>target/generated-docs</outputDirectory>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-asciidoctor</artifactId>
<version>4.0.0</version>
</dependency>
</dependencies>
</plugin>
撰寫測試範例
RestDocsTest 父類別實作
抽象出共用的測試設定與工具方法。
設定 MockMvc 並整合 Spring REST Docs。
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
@ExtendWith({ SpringExtension.class, RestDocumentationExtension.class })
@WebAppConfiguration
public class RestDocsTest {
protected MockMvc mockMvc;
@BeforeEach
public void setUp(WebApplicationContext webApplicationContext,
RestDocumentationContextProvider restDocumentation) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.build();
}
}
AppTest 類別實作
撰寫具體的測試方法,使用 MockMvc 執行 API 請求並自動產生文件片段。
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import sparrow.config.WebConfig;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import sparrow.controller.Controller;
@ContextConfiguration(classes = { WebConfig.class })
public class AppTest extends RestDocsTest {
@Test
public void documentGetStatusApi() throws Exception {
this.mockMvc.perform(get("/api/status"))
.andExpect(status().isOk())
.andDo(document("status-get",
responseFields(
fieldWithPath("status").description("API 處理狀態"),
fieldWithPath("message").description("詳細回應訊息"))));
}
}
AsciiDoc 文件撰寫
在專案根目錄建立 src/main/asciidoc/ 資料夾,並新增 index.adoc 檔案。這個檔案是測試片段的模板文件,包含了目錄結構與內容說明。
設定好後,當執行 Maven 的 package 階段時,asciidoctor-maven-plugin 會自動將 index.adoc 轉換為 HTML 文件,並將測試中產生的片段 (snippets) 插入對應位置。
在 target/generated-docs/ 目錄下會生成最終的 index.html,用於本地預覽或部署到伺服器。
標籤說明
- toc: left:將目錄放置在頁面左側。
- toclevels: 3:設定目錄的層級深度為 3
- sectnums:啟用章節自動編號。
= Sparrow Legacy API Guide
:toc: left
:toclevels: 3
:sectnums:
== Introduction
Sparrow 的 API 文件
== Status API
This API returns the current status of the application.
=== HTTP Request 範例
include::{snippets}/status-get/http-request.adoc[]
=== cURL Request 範例
include::{snippets}/status-get/curl-request.adoc[]
=== HTTP Response 範例
include::{snippets}/status-get/http-response.adoc[]
=== 回應欄位說明
include::{snippets}/status-get/response-fields.adoc[]
文件網頁
加入資源管理套件
- maven-resources-plugin: 將 Asciidoctor 生成的 HTML 文件複製到 Spring MVC 的靜態資源目錄中。
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.4.0</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/static/docs</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}/generated-docs</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
在 WebConfig 中加入資源處理器
@EnableWebMvc 註解會啟動一套預設的 Web 設定。
為了讓 Spring MVC 能對外提供我們打包好的靜態 HTML 文件,必須實作 WebMvcConfigurer 來註冊靜態資源路徑。
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "sparrow")
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/docs/**")
.addResourceLocations("classpath:/static/docs/");
}
}
測試網頁
在瀏覽器中訪問 http://localhost:8080/docs/index.html 就可以看到生成的 API 文件網頁了。
