OpenAPI 2.0 和OpenApi3.0比较
该部分内容取自于OpenAPI spec (swagger) v2 vs v3
多主机
OpenAPI 2.0 允许指定单个主机和基本路径,而schemes 属性允许指定http 和https,因此有效地启用了仅在方案中有所不同的两个主机。在 OpenAPI 3.0)中,新的根级别主机对象包含一组对象,其中包含主机、basePath 和方案属性。
通过将其构造为对象数组,可以支持 API 的任意数量的根 URL,并且它允许方案、主机和 basePath 属性之间更清晰的关联。它还减少了所需的根级别属性的数量,从而简化了文档结构。
此外,主机、基本路径和方案可以在路径项级别被覆盖。这应该可以更轻松地将单独主机上提供的功能合并到 API 描述中。
URL结构
目前,Swagger 2 允许您定义方案、主机和 baseUrl,它们会合并到您的 URL 中。现在,您可以拥有多个 URL,并且可以在任何地方定义它们,这意味着您可以像以前一样在基础上只有一个,或者如果基础 URL 不同,则特定端点可以拥有自己的服务器。
此外,现在允许路径模板。在 OpenAPI 3 中,仅在实际端点 URL 中允许这样做。您可以使用变量属性定义模板。
Swagger 2
info:
title: Swagger Sample App
host: example.com
basePath: /v1
schemes: ['http', 'https']
OpenAPI 3
servers:
- url: https://{subdomain}.site.com/{version}
description: The main prod server
variables:
subdomain:
default: production
version:
enum:
- v1
- v2
default: v2
路径项目也有一些细微的变化。他们现在可以接受描述。此外,您现在还可以为每个路径指定其自己的基本 URL(例如,http://login.example.com)。
URL verbs
您不再被允许为 GET 和 DELETE 定义请求body。最后,还有对 TRACE 的支持。
组件
Swagger 2 有定义的概念,但它们有些随意并且定义不那么明确。 OpenAPI 3 尝试将概念标准化为组件,这些组件是可以在多个位置重用的可定义对象。
开放 API 规范 3.0 提供了组件对象,其中可以包含:
schemas
parameters
responses
examples
security schemes
links
request bodies
headers
callbacks
This component object won’t affect the API until it is referenced somewhere in the API.
优点:如果一个 API 的多个操作需要类似的输入结构,则可以在组件下将输入结构定义为请求主体,并且可以在多个路径中重用。同样,标头、响应等也可以重用。
"components": {
"schemas": {
"Category": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
}
}
},
"Tag": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
}
}
}
},
"parameters": {
"skipParam": {
"name": "skip",
"in": "query",
"description": "number of items to skip",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
},
"limitParam": {
"name": "limit",
"in": "query",
"description": "max records to return",
"required": true,
"schema" : {
"type": "integer",
"format": "int32"
}
}
},
"responses": {
"NotFound": {
"description": "Entity not found."
},
"IllegalInput": {
"description": "Illegal input for operation."
},
"GeneralError": {
"description": "General Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GeneralError"
}
}
}
}
}
}
请求格式
Swagger 2 最令人困惑的方面之一是 body/formData。它们是参数的子集——你只能有一个或另一个——如果你使用 body,格式与其余参数不同。 (你只能有 on body 参数,名称不相关,格式不同等等。)
现在,body 已移至其自己的名为 requestBody 的部分,并且 formData 已合并到其中。
此外,cookies 已被添加为参数类型(除了现有的标头、路径和查询选项之外)。
Swagger 2
"/pets/{petId}":
post:
parameters:
- name: petId
in: path
description: ID of pet to update
required: true
type: string
- name: user
in: body
description: user to add to the system
required: true
schema:
type: array
items:
type: string
OpenAPI 3
"/pets/{petId}":
post:
requestBody:
description: user to add to the system
required: true
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
examples:
- name: Fluffy
petType: Cat
- http://example.com/pet.json
parameters:
- name: petId
in: path
description: ID of pet to update
required: true
type: string
新的 requestBody 支持不同的媒体类型(内容是 mimetypes 的数组,例如 application/json 或 text/plain,尽管您可以使用 / 表示支持所有类型)。
对于参数,您有两种定义方式的选择。您可以定义一个模式(如 2.0 中所示),它可以让您描述该项目。或者,如果更复杂,您可以使用 content,这与 requestBody 相同。
Request body content negotiation
3.0 版本提供了支持内容协商的 requestBody,以便您可以为各种媒体类型定义不同的架构和示例。 requestBody 允许 Web 服务接受和返回不同格式的数据,例如图像、纯文本、XML 和 JSON。它还允许您提供一个或多个示例。
案例 (Examples)
requestBody 有很多新功能。您现在可以为 requestBody 提供一个示例(或示例数组)。这非常灵活(您可以传递完整的示例、引用,甚至示例的 URL)。
链接(Linking)
链接是 OpenAPI 3 最有趣的新增功能之一。它有点复杂,但可能非常强大。这基本上是描述“接下来会发生什么”的一种方式。 (对于熟悉的人来说,它与 HATEOAS / 超媒体 API 具有相同的风格。)
假设您有一个用户,它有一个 addressId。这个addressId 本身是没什么用的。您可以使用链接来展示如何“扩展”它,并获取完整的地址。
paths:
/users/{userId}:
get:
responses:
200:
links:
address:
operationId: getAddressWithAddressId
parameters:
addressId: ‘$response.body#/addressId’
看看那里发生了什么?在 /users/{userId} 的响应中,我们返回一个 addressId。这些链接描述了我们如何通过引用 $response.body#/addressId 来获取地址。
另一个用例是分页。如果您获取 100 个结果,链接可以显示如何获取结果 101-200。它很灵活,这意味着它可以处理从限制到光标的任何分页方案。
为此,3.0 草案规范引入了 links 对象,以便描述基于从初始资源检索到的信息可以访问哪些新资源。这不一定是超媒体驱动的,因为新资源的 URL 尚未嵌入到返回的有效负载中,但它们是根据 OpenAPI 规范中定义的规则构建的。引入了新的表达式语法,以允许响应中的信息与链接操作中的参数相关联。
安全(Security)
对安全性进行了一系列更改!它已被重命名,OAuth2 流名称已更新,您可以拥有多个流,并且支持 OpenID Connect。基本类型已重命名为http,现在安全性可以有一个方案和一个bearerFormat。
Swagger 2
securityDefinitions:
UserSecurity:
type: basic
APIKey:
type: apiKey
name: Authorization
in: header
security:
- UserSecurity: []
- APIKey: []
OpenAPI 3
components:
securitySchemes:
UserSecurity:
type: http
scheme: basic
APIKey:
type: http
scheme: bearer
bearerFormat: TOKEN
security: - UserSecurity: []
- APIKey: []
回调(Callbacks)
Webhook 以发布/订阅模式利用 HTTP,它们已成为 API 提供商(包括 Slack、GitHub 和许多其他流行服务)中的流行模式。 Webhooks 使用简单,并且非常适合现有的基于 HTTP 的 API 风格。然而,对 OpenAPI 规范的一个批评是它无法描述出站 HTTP 请求及其预期响应。新的回调对象使这成为可能。回调对象可以附加到订阅操作,以描述订阅者可能期望的出站操作。
JSON Schema
许多请求都要求扩展 OpenAPI 规范允许包含的 JSON 模式的更复杂功能的 JSON 模式子集。在 2.0 规范流程中,代码生成的潜在工具复杂性促使排除 anyOf 和 oneOf。然而,许多用户要求放宽该限制,即使这会损害对这些功能的工具支持。这是规范设计中的巨大挑战之一,在做出这样的选择时,要知道是为人们提供可能会割伤自己的锋利工具,还是依靠经验来拒绝负担,这两者之间的关系是否更好?这个责任太大了。虽然OpenAPI 2.0采取了更为保守的方法,但用户群的经验已经变得更加丰富,因此一些限制正在取消,用户将不得不做出明智的选择。
Type 可以是数组
在 OpenAPI 的早期版本中,类型只能是单个字符串。但在 JSON Schema 中,类型可以是字符串数组。在 2.0 版本中没有解决此问题的方法,但在 3.0 版本中,您可以使用 oneOf 选择多种类型:
oneOf:
- type: string
- type: integer
With OpenAPI 3.1, the specification now supports type as an array:
type: [string, integer]
Type 不支持 null类型
OpenAPI 2.0 和 3.0 都不支持 null 作为类型,但 JSON Schema 确实支持 null 类型。 OpenAPI 3.0 包含字段名称 nullable,如果您希望值为 null,可以将其设置为 true:
type: string
nullable: true
不过,3.1 版本中添加了对 null 类型的支持,并且删除了 nullable 类型。
type: [string, “null”]
升级Swagger
依赖
替换依赖
旧依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
替换为新依赖:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
修改配置
- 移除注解@EnableSwagger2(普通springmvc项目还需加上@EnableOpenApi)
- 文档类型改为OAS_30
@Configuration
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30) // v2 不同
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.swaggerv3.controller"))
.build();
}
}