OpenAPI Generator 可根据 OpenAPI yaml 规范生成代码,并支持多种语言。
如何使用 OpenAPI #
本节介绍如何创建一个基本的 OpenAPI yaml 规范,并用它为 Spring Boot 应用程序生成服务器端代码。
Create OpenAPI spec #
首先要做的是为您的应用程序设计 OpenAPI 规范。您将设计一个客户 API。该 API 允许您创建一个客户,并根据其 ID 检索该客户。现实生活中的应用程序接口会更加复杂,但我们还是保持简单。
使用 Swagger 编辑器 是设计 API 的简便方法。它会立即反馈您的规范是否有错误,并即时生成 Swagger 文档。
OpenAPI 规范的 header 包含一些有关 API 的元数据,如标题、版本、API 运行的服务器等。标签可用于对资源进行分组,从而为您提供更多概览。
openapi: "3.0.2"
info:
title: API Customer
version: "1.0"
servers:
- url: https://localhost:8080
tags:
- name: Customer
description: Customer specific data.
paths 部分包含资源规范。您定义的第一个资源是创建 Customer 的资源,将通过包含 JSON 主体的 POST 方式创建。生成器将使用 operationId
为该资源创建方法名称。为简单起见,只考虑成功响应。模式指的是 JSON 主体,将在本节后面介绍。
/customer:
post:
tags:
- Customer
summary: Create Customer
operationId: createCustomer
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
responses:
'200':
description: OK
content:
'application/json':
schema:
$ref: '#/components/schemas/CustomerFullData'
第二个资源允许您检索客户。该资源也需要一个包含要检索的 customerId 的路径参数。如果 ID 不存在,将返回 NOT FOUND
的响应。
/customer/{customerId}:
get:
tags:
- Customer
summary: Retrieve Customer
operationId: getCustomer
parameters:
- name: customerId
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: OK
content:
'application/json':
schema:
$ref: '#/components/schemas/CustomerFullData'
'404':
description: NOT FOUND
最后,在组件部分,定义了使用的模式。除了 ID 之外,Customer 模式和 CustomerFullData 模式共享所有属性。为了提高可维护性,可以使用 allOf 属性。
components:
schemas:
Customer:
type: object
properties:
firstName:
type: string
description: First name of the customer
lastName:
type: string
description: Last name of the customer
CustomerFullData:
allOf:
- $ref: '#/components/schemas/Customer'
- type: object
properties:
customerId:
type: integer
description: The ID of the customer
format: int64
description: Full data of the customer.
该应用程序的 OpenAPI 规范现已完成。
Create Spring Boot Application #
要创建 Spring Boot 应用程序,请访问 start.spring.io,选择最新稳定的 Spring Boot 版本、Java 17 并添加 Spring Web 依赖关系。下载生成的项目并将其打开到您喜欢的集成开发环境中。在 src/main/resources 目录中添加 OpenAPI 规范,名称为 customer.yml。
您将使用 Open API Generator Maven 插件,因此请将该插件添加到 pom 文件的构建部分。由于您使用的是 Spring Boot 应用程序,因此使用 spring 作为 generatorName,并使用 inputSpec 属性设置 customer.yml 文件的路径。
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>5.3.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/customer.yml</inputSpec>
<generatorName>spring</generatorName>
</configuration>
</execution>
</executions>
</plugin>
执行以下命令生成代码:
$ mvn clean compile
编译失败,出现以下错误:
package io.swagger.annotations does not exist
package io.swagger.annotations does not exist
package org.openapitools.jackson.nullable does not exist
cannot find symbol
为了解决这些问题,需要在 pom 文件中添加以下依赖项:
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.1</version>
</dependency>
再次运行编译会出现以下错误:
package springfox.documentation.builders does not exist
package springfox.documentation.builders does not exist
package springfox.documentation.service does not exist
package springfox.documentation.service does not exist
package springfox.documentation.spi does not exist
package springfox.documentation.spring.web.paths does not exist
package springfox.documentation.spring.web.paths does not exist
package springfox.documentation.spring.web.plugins does not exist
package springfox.documentation.swagger2.annotations does not exist
在 pom 文件中添加以下依赖项可以解决这些错误:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.0</version>
</dependency>
仔细看看生成了什么。导航至 target/generated-sources/open-api
目录,在该目录中可以找到生成的文件。以下目录包含生成的文件:
src/main/org/openapitools/api
: 是 Spring 控制器的一个接口,也是一个实现src/main/org/openapitools/configuration
: 是 Swagger 文档的控制器src/main/org/openapitools/model
: 基于 API 规范的 API 模型src/main/org/openapitools
:OpenAPI2SpringBoot
是一个 SpringBootApplication
当你想运行 Spring Boot 应用程序时,你会遇到一个错误,因为 Spring Boot 无法确定它需要运行哪个 SpringBootApplication :
$ mvn spring-boot:run
由此产生的错误是 :
Unable to find a single main class from the following candidates [org.openapitools.OpenAPI2SpringBoot, com.mydeveloperplanet.myopenapiplanet.MyOpenApiPlanetApplication
默认情况下会生成大量代码,也许比你需要的还要多。下一段将介绍如何调整配置。
Configure OpenAPI plugin #
除了 OpenAPI 插件的 Maven 部分记录的所有选项外,还有许多额外的选项可在 OpenAPI 插件配置部分的 configOptions 部分进行配置。可通过在配置部分添加 configHelp 属性来显示可用选项。
<configuration>
<inputSpec>${project.basedir}/src/main/resources/customer.yml</inputSpec>
<generatorName>spring</generatorName>
<configHelp>true</configHelp>
</configuration>
在此列表中,您将使用 interfaceOnly 属性,它只会为控制器和 API 模型生成接口。
<configuration>
...
<configOptions>
<interfaceOnly>true</interfaceOnly>
</configOptions>
</configuration>
此时,还可以删除之前添加的 Springfox 依赖项。这些都不再需要了。
从生成的代码中还可以看到,代码是在 org.openapitools 包中生成的。你可能希望这是你自己的软件包名称,这可以通过一些基本属性来配置。通过 packageName 属性,您可以设置默认的软件包名称。不过,还必须设置 apiPackage 和 modelPackage 属性,否则这些属性仍将在 org.openapitools 包中生成。在配置部分添加以下内容。
<configuration>
....
<packageName>com.mydeveloperplanet.myopenapiplanet</packageName>
<apiPackage>com.mydeveloperplanet.myopenapiplanet.api</apiPackage>
<modelPackage>com.mydeveloperplanet.myopenapiplanet.model</modelPackage>
....
</configuration>
生成的控制器界面如下:
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2022-01-15T12:51:43.809971036+01:00[Europe/Amsterdam]")
@Validated
@Api(value = "customer", description = "the customer API")
public interface CustomerApi {
default Optional<NativeWebRequest> getRequest() {
return Optional.empty();
}
/**
* POST /customer : Create Customer
*
* @param customer (optional)
* @return OK (status code 200)
*/
@ApiOperation(value = "Create Customer", nickname = "createCustomer", notes = "", response = CustomerFullData.class, tags={ "Customer", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = CustomerFullData.class) })
@RequestMapping(
method = RequestMethod.POST,
value = "/customer",
produces = { "application/json" },
consumes = { "application/json" }
)
default ResponseEntity<CustomerFullData> createCustomer(@ApiParam(value = "") @Valid @RequestBody(required = false) Customer customer) {
getRequest().ifPresent(request -> {
for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
String exampleString = "null";
ApiUtil.setExampleResponse(request, "application/json", exampleString);
break;
}
}
});
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
...
Use Generated Code #
在应用程序中,首先要在包 domain 中创建一个 Customer 类。
public class Customer {
private Long customerId;
private String firstName;
private String lastName;
// Getters and setters
}
创建一个 CustomerController,实现生成的 CustomerApi 接口。
创建 Customer 是一种基本的实现方式,您可以将 Customer 添加到 HashMap 中:计算索引是键,域客户对象是值。在实际应用中,您将把客户保存到数据库中。
检索客户时,首先要检查所请求的 ID 是否存在于 HashMap 中。找到 ID 后,Customer 域对象将转换为 Customer API 模型对象并返回给请求者。如果未找到 ID,则会返回 NOT FOUND 响应。
@RestController
public class CustomerController implements CustomerApi {
private final HashMap<Long, com.mydeveloperplanet.myopenapiplanet.domain.Customer> customers = new HashMap<>();
private Long index = 0L;
@Override
public ResponseEntity<CustomerFullData> createCustomer(Customer apiCustomer) {
com.mydeveloperplanet.myopenapiplanet.domain.Customer customer = new com.mydeveloperplanet.myopenapiplanet.domain.Customer();
customer.setCustomerId(index);
customer.setFirstName(apiCustomer.getFirstName());
customer.setLastName(apiCustomer.getLastName());
customers.put(index, customer);
index++;
return ResponseEntity.ok(domainToApi(customer));
}
@Override
public ResponseEntity<CustomerFullData> getCustomer(Long customerId) {
if (customers.containsKey(customerId)) {
return ResponseEntity.ok(domainToApi(customers.get(customerId)));
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
private CustomerFullData domainToApi(com.mydeveloperplanet.myopenapiplanet.domain.Customer customer) {
CustomerFullData cfd = new CustomerFullData();
cfd.setCustomerId(customer.getCustomerId());
cfd.setFirstName(customer.getFirstName());
cfd.setLastName(customer.getLastName());
return cfd;
}
}
运行 Spring Boot 应用程序:
$ mvn spring-boot:run
添加 Consumer,并查找
$ curl -i -X 'POST' \
> 'http://localhost:8080/customer' \
> -H 'accept: application/json' \
> -H 'Content-Type: application/json' \
> -d '{
> "firstName": "Foo",
> "lastName": "Bar"
> }'
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 15 Jan 2022 11:42:47 GMT
{"firstName":"Foo","lastName":"Bar","customerId":0}
$ curl -i -X 'POST' \
> 'http://localhost:8080/customer' \
> -H 'accept: application/json' \
> -H 'Content-Type: application/json' \
> -d '{
> "firstName": "John",
> "lastName": "Doe"
> }'
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 15 Jan 2022 11:43:11 GMT
{"firstName":"John","lastName":"Doe","customerId":1}
$ curl -i http://localhost:8080/customer/1
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 15 Jan 2022 11:45:21 GMT
{"firstName":"John","lastName":"Doe","customerId":1}
$ curl -i http://localhost:8080/customer/2
HTTP/1.1 404
Content-Length: 0
Date: Sat, 15 Jan 2022 11:46:18 GMT
Add OpenAPI Documentation #
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.12</version>
</dependency>
在浏览器中导航至 http://localhost:8080/swagger-ui.html,即可显示 OpenAPI 文档,并可在此处下载 OpenAPI yaml 规范。
当你仔细查看文档时,会发现它与 Swagger 编辑器中显示的文档有所不同。springdoc 依赖项默认会从源代码生成文档,并使用生成的文档。如何配置 springdoc 以使用 customer.yml 文件?
首先,您需要将 customer.yml 文件移至 src/main/resources/static/customer.yml 目录。这也意味着你需要更改 pom 中的 Open API 生成器配置。
<configuration>
<inputSpec>${project.basedir}/src/main/resources/static/customer.yml</inputSpec>
...
</configuration>
在 application.properties 文件中添加以下属性
springdoc.swagger-ui.url=/customer.yml
URL 现在显示的是您创建的 customer.yml 中定义的 API