Spring REST Docs 文檔查詢參數

REST,Spring Web
Remote
1
03:42 AM · Dec 01 ,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. Tests With Documentation

Spring REST Docs 支持主要的 REST 測試框架。我們將會考慮 MockMvcWebTestClient 和 REST-assured 的示例。然而,所有這些的思路和結構都大致相同。

此外,我們將使用 JUnit 5 作為測試用例的基礎,但可以使用 JUnit 4

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

@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. WebMvcTestMockMvc

總的來説,這種方法與前面的方法非常相似。它也需要正確的設置:

@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:

Request parameters

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

6. 結論

文檔是軟件開發的重要組成部分。開發者承認這一點,但只有少數人始終堅持編寫或維護文檔。Spring REST Docs 允許我們以最小的努力,基於代碼而非我們對 API 功能的理解,生成良好的文檔。

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

發佈 評論

Some HTML is okay.