知識庫 / Spring / Spring Boot RSS 訂閱

從 OpenAPI 規範生成 Spring Boot 中的 HTTP 客户端

HTTP Client-Side,Spring Boot
HongKong
8
10:37 AM · Dec 06 ,2025

1. 引言

在實現需要某種形式網絡通信的服務時,這通常是一個常見的任務。在這種情況下,我們通常需要編寫服務器端和客户端代碼以啓用該通信。

在本文中,我們將學習如何使用 OpenAPI 規範自動生成服務器端和客户端代碼,重點關注客户端生成的代碼。

2. 定義演示 API 的 YAML 文件

OpenAPI 規範使用 YAML 文件定義來描述 API 的結構。 服務器和客户端應用程序都可以無縫地導入該定義以生成服務器和客户端代碼。

為了説明客户端代碼生成,我們使用 weatherapi.yaml 文件定義一個演示天氣 API:

openapi: 3.0.3
info:
  title: Current Weather API
  description: |
    Get real-time weather information for cities worldwide.
  version: 1.0.0

paths:
  /weather:
    get:
      summary: Get current weather data
      description: Retrieve current weather information for a specified city
      operationId: getCurrentWeather
      parameters:
        - name: city
          in: query
          required: true
          schema:
            type: string
        - name: units
          in: query
          required: false
          schema:
            type: string
            enum: [ celsius, fahrenheit ]
            default: celsius
      responses:
        '200':
          description: Successful weather data retrieval
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WeatherResponse'
        '404':
          description: City not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

components:
  schemas:
    WeatherResponse:
      type: object
      required:
        - location
      properties:
        current:
          type: object
          required:
            - temperature
            - units
          properties:
            temperature:
              type: number
              format: double
            units:
              type: string
              enum: [ celsius, fahrenheit ]
            timestamp:
              type: string
              format: date-time

    ErrorResponse:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
        message:
          type: string

API 具有一個單一的 REST 端點,用於獲取當前天氣並返回成功響應或錯誤響應。

3. 配置項目

我們需要一些依賴項和一個 Maven 插件配置,以便從我們的 YAML 文件生成 Java 代碼。

3.1. 添加 Maven 依賴

為了正確編譯生成的代碼,我們需要添加 `spring-boot-starter-webspring-starter-validation 依賴,以便從這些依賴中獲取一些 Web 類和註解。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

3.2. 配置 OpenAPI Maven 插件

我們還應在 OpenAPI 依賴項中設置 openapi-generator-maven-plugin 的執行,以生成客户端代碼:

<plugins>
    <plugin>
        <groupId>org.openapitools</groupId>
        <artifactId>openapi-generator-maven-plugin</artifactId>
        <version>${openapi-generator.version}</version>
        <executions>
            <execution>
                <id>generate-weather-api</id>
                <goals>
                    <goal>generate</goal>
                </goals>
                <configuration>
                    <inputSpec>${project.basedir}/src/main/resources/api/weatherapi.yaml</inputSpec>
                    <generatorName>spring</generatorName>
                    <configOptions>
                        <openApiNullable>false</openApiNullable>
                        <useJakartaEe>false</useJakartaEe>
                        <documentationProvider>none</documentationProvider>
                        <annotationLibrary>none</annotationLibrary>
                        <apiPackage>com.baeldung.tutorials.openapi.generatehttpclients.api</apiPackage>
                        <modelPackage>com.baeldung.tutorials.openapi.generatehttpclients.api.model</modelPackage>
                    </configOptions>
                </configuration>
            </execution>
        </executions>
    </plugin>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
</plugins>

在上面的片段中,我們定義了一個 Maven 執行,用於從我們的 YAML 文件生成代碼,該代碼來自 配置 集合:

  • inputSpec: 我們的 YAML 文件的位置
  • generatorName: 來自 可用選項之一。我們通常對 javaspring 生成器感興趣
  • openApiNullable: 代碼是否應該使用 Jackson Nullable 庫
  • useJakartaEe: 代碼是否應該使用 jakarta 命名空間而不是 javax
  • documentationProvider: API 文檔的來源。它要麼是 none,要麼是 source。後者的意思是它將根據 YAML 文件中的描述進行文檔化。
  • annotationLibrary: 如果 documentationProvider 設置為非 none,則使用的註解庫
  • apiPackage:: API 相關類目標包
  • modelPackage:: 模型類目標包

另一個未在其中列出的重要 配置選項library。這是生成的代碼使用的庫。

我們使用默認的 library,一個簡單的測試實現,使用 Spring 的原生 webhttp 包。對於那篇文章,我們只對基於 OpenAPI Specification 文件的可直接使用的 REST 客户端感興趣,因此該基本測試實現僅用於説明目的。

OpenAPI 提供 不同 library 選項,通過將 generatorName 設置為 spring,例如使用自動配置的 Spring Cloud OpenFeign bean 實現。

此外,將 generatorName 設置為 java 提供了更廣泛的 庫選項,包括 RestTemplate, OpenFeign, RestAssured

4. 生成 API 客户端

在完成基本的 OpenAPI 配置後,可以使用 Maven 插件通過以下命令生成代碼:

mvn compile

之後,我們就能在 target 文件夾下的路徑中看到生成的類:

在那裏我們可以看到兩個重要的文件:WeatherApi 接口WeatherApiController。 讓我們快速瀏覽一下 OpenAPI 生成的 WeatherApi

public interface WeatherApi {
    @RequestMapping(
        method = RequestMethod.GET,
        value = "/weather",
        produces = { "application/json" }
    )
    
    default ResponseEntity<WeatherResponse> getCurrentWeather(
        @NotNull  @Valid @RequestParam(value = "city", required = true) String city,
         @Valid @RequestParam(value = "units", required = false, defaultValue = "celsius") String units
    ) {
        // a generated test implementation
    }
}

在清理生成代碼的冗餘部分後,我們得到了getCurrentWeather()方法,該方法使用/weather端點,並使用@RequestMapping註解定義了該端點。該方法使用我們定義的YAML規範進行序列化、驗證和提供默認值,並使用@Valid, @NotNull@RequestParam註解。

然後,如果查看WeatherApiController:

@Controller
@RequestMapping("${openapi.currentWeather.base-path:}")
public class WeatherApiController implements WeatherApi {
    // a generated test implementation
}

OpenAPI 還生成了一個 Spring 自配置的 WeatherApiController 實現,它在 @RequestMapping 中使用環境變量,因此導入該模塊的客户端可以配置 API 的 base path例如,在客户端,我們可以導入包含 api 包的導出模塊,並僅設置 base-path 資源,自動注入 WeatherApi

@Service
public class GetWeatherService {
    private final WeatherApi weatherApi;

    public GetWeatherService(WeatherApi weatherApi) {
        this.weatherApi = weatherApi;
    }

    public WeatherResponse getCurrentWeather(String city, String units) {
        var response = weatherApi.getCurrentWeather(city, units);

        if (response.getStatusCodeValue() < 399) {
            return response.getBody();
        }

        throw new RuntimeException("Failed to get current weather for " + city);
    }
}

在客户的application.yaml中:

openapi:
  currentWeather:
    base-path: https://localhost:8080

5. OpenAPI 的優勢

OpenAPI 生成器在服務暴露端點並有依賴該端點的客户端時非常實用。 在這種情況下,我們可以維護兩個模塊,一個用於客户端,另一個用於服務器,兩者都從相同的 OpenAPI YAML 規範中讀取 API 契約。 因此,兩個模塊都會與最新的 API 契約保持同步,從而最大限度地降低客户端和服務器應用程序之間契約中斷的風險。 這需要對客户端模塊的版本管理進行更細粒度的管理,並且客户端需要自行保持庫的更新。

值得注意的是,使用代碼生成器可以幫助我們跳過手動代碼實現的一部分。 因此,我們可以減少在客户端和服務器之間建立通信所需的努力,因為雙方的代碼都可以自動生成。

例如,在同一開發人員需要同時實現服務器和客户端代碼的情況下,可以有益於將這兩個努力減少為僅創建 OpenAPI YAML 規範文件,並讓生成器完成任務。

6. OpenAPI 的缺點

作為任何代碼生成器的那樣,我們存在無法完全控制生成代碼外觀的缺點。對於需要高度定製和複雜客户端代碼的需求,使用生成器可能令人痛苦,因為我們缺乏對生成內容進行控制。

例如,OpenAPI 目前會生成可變模型類用於 API 響應,而這可以利用 Java Records 以簡化和提高安全性。

此外,使用生成代碼,我們還缺乏對調試、故障排除和修復代碼的控制,因為我們無法對其進行修改。

最後,它還引入了另一個依賴項,並伴隨着一系列傳遞依賴項,這需要更多的工作來更新並避免不兼容性和安全問題。

7. 結論

在本文中,我們學習瞭如何使用 OpenAPI 規範和 OpenAPI Maven 插件自動生成客户端代碼。我們處理了使用 spring-web 依賴項和 OpenAPI 規範 YAML 文件中定義的 API 生成簡單 REST 客户端的典型情況。

我們還研究了使用該庫生成代碼的優點和缺點,以供我們使用。

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

發佈 評論

Some HTML is okay.