知識庫 / REST RSS 訂閱

Spring REST Docs 文檔查詢參數

REST,Spring Web
HongKong
4
03:35 AM · Dec 06 ,2025

1. 概述

文檔對於我們打算與世界分享的任何代碼都至關重要,尤其是在代碼相對複雜的情況下。優秀的API文檔不僅能吸引開發者使用它,還能展示產品的質量。 一篇寫得不清楚的文檔可能也意味着一個寫得不清楚的API。

然而,開發者更喜歡為機器編寫代碼,而不是為人類編寫文本。

在本教程中,我們將探討如何將編寫文檔與編寫API結合使用,以及如何使用Spring REST Docs。我們將以查詢參數文檔為例。

2. API

讓我們考慮一個簡單的 API,它只有一個端點:

@RestController
@RequestMapping("/books")
public class BookController {
    private final BookService service;

    public BookController(BookService service) {
        this.service = service;
    }

    @GetMapping
    public List<Book> getBooks(@RequestParam(name = "page") Integer page) {
        return service.getBooks(page);
    }
}

此端點返回我們在網站上提供的書籍集合。然而,由於書籍數量龐大,我們無法返回所有書籍。客户端提供我們目錄的頁碼,我們僅向他們發送該頁的信息。

我們決定使該參數為必需參數。在這種情況下,它是一個默認設置。通過這種方式,我們提高了服務的性能,並防止客户端一次請求過多的數據。

但是,我們必須提供關於我們決策的信息,並解釋客户端應該遵循的規則。在這種情況下,如果參數不存在,客户端將收到錯誤消息。

3. 文檔説明

通常編寫文檔的做法是編寫文檔,也就是説,開發者需要將同一內容編寫兩次:一次在代碼中,另一次在文本中,解釋如何與系統交互。 然而,這種做法既浪費時間,也不能假設所有開發者都會遵循。

文檔是一種相當正式的文件,旨在追求清晰度,而不是富有啓發性的見解、巧妙的措辭或創新的情節結構。 因此,為什麼不從代碼中生成文檔呢? 這樣,我們就不必編寫相同的代碼,並且所有更改都會反映在文檔中。

Spring REST Docs 正確地做到這一點。 但是,它不是從代碼中生成文檔,因為它提供的上下文很少,而是從測試中生成文檔。 這樣,我們就可以表達相當複雜的用例和示例。 另一個好處是,如果我們的測試失敗,文檔將不會被生成。

4. 包含文檔的測試

Spring REST Docs 支持主要的 REST 測試框架。 我們將以 MockMvcWebTestClient 和 REST-assured 為例。 然而,所有這些框架的主要思想和結構都將相似。

此外,我們將使用 JUnit 5 作為測試用例的基礎,但也可以使用 JUnit 4 設置 Spring REST Docs。

以下所有測試方法都需要額外的擴展:

@ExtendWith({RestDocumentationExtension.class, SpringExtension.class})

這些是用於文檔生成的功能模塊。

4.1. WebTestClient

讓我們從 WebTestClient 開始,這是一種更現代的 REST 測試方法。正如之前提到的,我們需要通過添加額外的擴展來擴展測試類。 並且,我們需要對其進行配置:

@BeforeEach
public void setUp(ApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
    this.webTestClient = WebTestClient.bindToApplicationContext(webApplicationContext)
      .configureClient()
      .filter(documentationConfiguration(restDocumentation))
      .build();
}

之後,我們可以編寫一個測試,不僅可以檢查我們的API,還可以提供有關請求的信息:

@Test
@WithMockUser
void givenEndpoint_whenSendGetRequest_thenSuccessfulResponse() {
    webTestClient.get().uri("/books?page=2")
      .exchange().expectStatus().isOk().expectBody()
      .consumeWith(document("books",
        requestParameters(parameterWithName("page").description("The page to retrieve"))));
}

4.2. <em >WebMvcTest</em><em >MockMvc</em>

一般來説,此方法與前一個方法非常相似。它也需要正確的設置:

@BeforeEach
public void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
    this.mockMvc = webAppContextSetup(webApplicationContext)
      .apply(documentationConfiguration(restDocumentation))
      .alwaysDo(document("{method-name}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())))
      .build();
}

測試方法看起來基本相同,只是我們使用了 MockMvc 及其 API:

@Test
void givenEndpoint_whenSendGetRequest_thenSuccessfulResponse() throws Exception {
    mockMvc.perform(get("/books?page=2"))
      .andExpect(status().isOk())
      .andDo(document("books",
        requestParameters(parameterWithName("page").description("The page to retrieve"))));
}

4.3. REST-assured

最後,我們來看一個使用 REST-assured 的示例。由於這個示例需要一個運行中的服務器,因此我們不應使用 @WebMvcTest@AutoconfigureMockMvc。在這裏,我們使用 @AutoconfigureWebMvc 並提供正確的端口:

@BeforeEach
void setUp(RestDocumentationContextProvider restDocumentation, @LocalServerPort int port) {
    this.spec = new RequestSpecBuilder()
      .addFilter(documentationConfiguration(restDocumentation))
      .setPort(port)
      .build();
}

然而,測試結果總體上保持一致:

@Test
@WithMockUser
void givenEndpoint_whenSendGetRequest_thenSuccessfulResponse() {
    RestAssured.given(this.spec).filter(document("users", requestParameters(
        parameterWithName("page").description("The page to retrieve"))))
      .when().get("/books?page=2")
      .then().assertThat().statusCode(is(200));
}

5. 生成文檔

然而,在此階段,我們還沒有生成文檔。要獲得結果,我們需要進行額外的步驟。

5.1. 生成片段

我們可以運行測試後在目標文件夾中找到生成的片段。但是,我們可以配置輸出目錄以定義存儲片段的另一個位置。通常,它們如下所示:

[source,bash]
----
$ curl 'http://localhost:8080/books?page=2' -i -X GET
----

同時,我們還可以看到關於我們參數的信息,這些信息存儲在 .adoc 文件中。

|===
|Parameter|Description

|`+page+`
|The page to retrieve

|===

5.2 文檔生成

下一步是為 AsciiDoctor 提供配置,以便生成更易讀的 HTML 文檔。 AsciiDoc 是一種簡單但功能強大的標記語言。 我們可以使用它進行各種用途,例如生成 HTML 和 PDF 文檔或編寫書籍。

因此,為了生成 HTML 文檔,我們需要制定 HTML 模板:

= Books With Spring REST Docs

How you should interact with our bookstore:

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

.request-parameters
include::{snippets}/books/request-parameters.adoc[]

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

在我們的情況下,我們使用一種簡單的格式,但也可以創建更復雜、更定製化的格式,使其更具吸引力和信息量。 AsciiDoc 的靈活性有助於我們實現這一點。

5.3. 生成的 HTML

在正確設置和配置完成後,當我們能夠將生成目標附加到 Maven 階段時:

<executions>
    <execution>
        <id>generate-docs</id>
        <phase>package</phase>
        <goals>
            <goal>process-asciidoc</goal>
        </goals>
        <configuration>
            <backend>html</backend>
            <doctype>book</doctype>
            <attributes>
                <snippets>${snippetsDirectory}</snippets>
            </attributes>
            <sourceDirectory>src/docs/asciidocs</sourceDirectory>
            <outputDirectory>target/generated-docs</outputDirectory>
        </configuration>
    </execution>
</executions>

我們可以在指定執行 mvn 命令並觸發生成過程。我們之前定義的模板會渲染以下 HTML:

我們可以將此流程附加到我們的流水線中,並始終擁有相關且準確的文檔。 另一個好處是,此流程減少了手動工作,這既浪費又容易出錯。

6. 結論

文檔是軟件開發中不可或缺的一部分。開發人員對此表示認可,但只有少數人能夠始終如一地編寫或維護文檔。Spring REST Docs 允許我們通過基於代碼而非我們對 API 功能的理解,以最小的努力生成高質量的文檔。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.