OpenAPI 规范(OAS),是定义一个标准的、与具体编程语言无关的RESTful API的规范。OpenAPI 规范使得人类和计算机都能在“不接触任何程序源代码和文档、不监控网络通信”的情况下理解一个服务的作用。如果您在定义您的 API 时做的很好,那么使用 API 的人就能非常轻松地理解您提供的 API 并与之交互了。
如果您遵循 OpenAPI 规范来定义您的 API,那么您就可以用文档生成工具来展示您的 API,用代码生成工具来自动生成各种编程语言的服务器端和客户端的代码,用自动测试工具进行测试等等。
Swagger是一套基于OpenApi的开源工具套装,可用于对api文档进行设计、生成和使用。主要包括以下工具:
OpenAPI的最根本的目的是为了描述接口本身。OpenAPI规范和Swagger工具通过多种方式来满足api开发的需要:
可以通过yaml或者json格式来定义openAPI文档。在本文中,将选择YAML格式。下面是一个OpenAPI 3.0文档的例子:
openapi: 3.0.0
info:
title: Sample API
description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
version: 0.1.9
servers:
- url: http://api.example.com/v1
description: Optional server description, e.g. Main (production) server
- url: http://staging-api.example.com
description: Optional server description, e.g. Internal staging server for testing
paths:
/users:
get:
summary: Returns a list of users.
description: Optional extended description in CommonMark or HTML.
responses:
'200': # status code
description: A JSON array of user names
content:
application/json:
schema:
type: array
items:
type: string
version
OpenAPI版本号,如:
openapi: 3.0.0
OpenAPI版本规定了API说明文档的总体结构 - 内容是什么,以及如何去写。OpenAPI 3.0可用的版本包括:3.0.0,3.0.1,3.0.2和3.0.3,它们在功能上都是相同的。
Info
该部分则包含API接口的基本信息:标题,描述(非必需),版本。
接口版本可以按照自己的规则命名,如major.minor.patch格式或者1.0-beta,年-月-日等都是可以的。
除了这些基本信息之外,info还支持其他关键字,如联系方式contact,许可license,服务协议和其他信息。
具体参见:Info Object.
Servers
servers部分指定了API server和基本URL。你可以定义一个或多个不同环境的server, 比如生产环境和沙箱环境的。
完整的API路径是server的URL和API的path结合起来的,在上面的示例中,/users意味着api路径为:http://api.example.com/v1/users
或者http://staging-api.example.com/users
。
Paths
paths部分定义了API接口的具体的终端地址,以及其支持的http方法。
一个请求定义包括:参数, 请求体 (如果有的话), 返回状态码(如200 OK 或 404 Not Found) 和响应内容。
Parameters
参数可以出现在URL路径里(/users/{userId}),查询字符串里(/users?role=admin),请求头里(X-CustomHeader: Value)或者cookies里(Cookie: debug=0)。你可以定义参数类型,格式,是否是必填的。如下所示:
paths:
/users/{userId}:
get:
summary: Returns a user by ID.
parameters:
- name: userId
in: path
required: true
description: Parameter description in CommonMark or HTML.
schema:
type : integer
format: int64
minimum: 1
responses:
'200':
description: OK
Request Body
如果一个请求发送了请求body参数,就需要使用requestBody关键字来描述参数内容和媒体类型。如下所示:
paths:
/users:
post:
summary: Creates a user.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
username:
type: string
responses:
'201':
description: Created
Responses
对于每一个请求, 你可以定义可能返回的状态码, 如200或404, 还有返回内容的schemas。模式可以在内部定义或者通过$ref进行引用。 下面是一个例子:
paths:
/users/{userId}:
get:
summary: Returns a user by ID.
parameters:
- name: userId
in: path
required: true
description: The ID of the user to return.
schema:
type: integer
format: int64
minimum: 1
responses:
'200':
description: A user object.
content:
application/json:
schema:
type: object
properties:
id:
type: integer
format: int64
example: 4
name:
type: string
example: Jessica Smith
'400':
description: The specified user ID is invalid (not a number).
'404':
description: A user with the specified ID was not found.
default:
description: Unexpected error
注意,HTTP 状态码必须用引号包起来,如: “200” (OpenAPI 2.0不需要引号)。
输入和输出模型
全局components/schemas部分用于定义API中使用的通用数据结构。 当一个模式schema需要的时候,它们可以通过 $ref 来进行引用。下面就是一个json对象:
{
"id": 4,
"name": "Arthur Dent"
}
在OpenAPI文档的输入输出部分描述如下:
components:
schemas:
User:
type: object
properties:
id:
type: integer
example: 4
name:
type: string
example: Arthur Dent
# Both properties are required
required:
- id
- name
在请求body中和响应body中的模式引用如下所示:
paths:
/users/{userId}:
get:
summary: Returns a user by ID.
parameters:
- in: path
name: userId
required: true
schema:
type: integer
format: int64
minimum: 1
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/User' # <-------
/users:
post:
summary: Creates a new user.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/User' # <-------
responses:
'201':
description: Created
Authentication
securitySchemes和security关键字用于描述鉴权方法。
components:
securitySchemes:
BasicAuth:
type: http
scheme: basic
security:
- BasicAuth: []
支持的鉴权方法有:
OpenAPI 3.0 允许你通过以下的security schemes来描述受保护的api:
如果你之前使用了OpenAPI 2.0, 那么你可以从以下几个方面获取到OpenAPI 3.0在安全认证方面的变化:
securityDefinitions
变更为securitySchemes
,并且移到了components
元素里面。type: basic
变更为 type: http
和 scheme: basic
和组合。type: http
是所有的HTTP安全模式的总体类型,包括 Basic
, Bearer
和其他,而且scheme关键字就能表明机制的类型。accessCode
变更为authorizationCode
,application
变更为clientCredentials
。关键字securitySchemes
和 security
用来描述安全性。你可以使用securitySchemes
来定义API接口的安全机制,并使用security
来为所有API或者某个操作申请具体的机制。
securitySchemes
先定义,再使用。也就是说必须先在components/securitySchemes部分定义安全机制,之后才能在API中去使用。以下就是所谓的安全机制类型和安全机制(securitySchemes):
每种安全机制所需的其他属性取决于其类型。以下是一些例子:
components:
securitySchemes:
BasicAuth:
type: http
scheme: basic
BearerAuth:
type: http
scheme: bearer
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
OpenID:
type: openIdConnect
openIdConnectUrl: https://example.com/.well-known/openid-configuration
OAuth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://example.com/oauth/authorize
tokenUrl: https://example.com/oauth/token
scopes:
read: Grants read access
write: Grants write access
admin: Grants access to admin operations
声明了securitySchemes之后,就可以将其应用到全部api或者某个具体的方法里了。在根元素级别定义的安全机制对全部api生效,在方法级别定义的安全策略只对这个方法生效。在下面的例子中,通过API key或者OAuth 2安全机制对api调用进行鉴权,这里的API key和OAuth 2引用了上文中定义的securitySchemes:
security:
- ApiKeyAuth: []
- OAuth2:
- read
- write
# The syntax is:
# - scheme name:
# - scope 1
# - scope 2
对于每个机制,您需要指定 API 调用所需的安全范围列表(如下所示),当然,这个范围仅用于 OAuth 2 和 OpenID Connect Discovery这两种安全机制;其他安全机制为空数组。security可以在单个操作中覆盖全局以使用不同的身份验证类型、不同的 OAuth/OpenID 范围或根本不进行身份验证:
paths:
/billing_info:
get:
summary: Gets the account billing info
security:
- OAuth2: [admin] # Use OAuth with a different scope
responses:
'200':
description: OK
'401':
description: Not authenticated
'403':
description: Access token does not have the required scope
/ping:
get:
summary: Checks if the server is running
security: [] # No security
responses:
'200':
description: Server is up and running
default:
description: Something is wrong
OAuth 2 和 OpenID Connect 使用范围来控制对各种用户资源的访问权限。例如,宠物商店的范围可能包括read_pets、write_pets、read_orders、write_orders、admin。申请时security,OAuth 2和OpenID Connect对应的条目需要指定特定操作(如果security在操作级别使用)或所有API调用(如果security在根级别使用)所需的范围列表。如下所示:
security:
- OAuth2:
- scope1
- scope2
- OpenId:
- scopeA
- scopeB
- BasicAuth: []
上文就提到过,所有的API终端都是与基本url相关联的,比如基本url为:https://api.example.com/v1
, 则终端 /users
实际的路径就是https://api.example.com/v1/users
。
在OpenAPI 3.0中, 可以使用servers数组来指定一个或多个基础url。在3.0版本中,servers 取代了OpenAPI 2.0中的host, basePath和schemes配置。每一个server都有一个url和一个可选的Markdown格式的描述。如下所示:
servers:
- url: https://api.example.com/v1 # The "url: " prefix is required
Server 的URL格式遵循 RFC 3986标准,通常如下:
scheme://host[:port][/path]
host可以是一个名称或者ip地址(IPv4 or IPv6)。OpenAPI 2.0中使用的WebSocket机制ws:// 和 wss:// 在OpenAPI 3.0中也是支持的。下面是一个server urls示例:
https://api.example.com
https://api.example.com:8443/v1/reports
http://localhost:3025/v1
http://10.0.81.36/v1
ws://api.example.com/v1
wss://api.example.com/v1
/v1/reports
/
如果server的URL地址是相对路径,那么它将被解析为OpenAPI定义文件所在主机的相对路径,如/v2,OpenAPI文件为:http://localhost:3001/openapi.yaml
,则server的url解析为:http://localhost:3001/v2
。
注意: Server URL不能包括查询字符串,比如这样的:
https://api.example.com/v1?route=
如果servers数组没有提供或者是空的,那么url默认值为/:
servers:
- url: /
server URL的任何部分– scheme协议, 主机名(或其中的一部分), 端口, 自路径 – 都可以使用变量来进行参数化处理。比如下面的例子:
servers:
- url: https://{customerId}.saas-app.com:{port}/v2
variables:
customerId:
default: demo
description: Customer ID assigned by the service provider
port:
enum:
- '443'
- '8443'
default: '443'
server变量不像path部分的参数一样使用schema,而是使用字符串。变量可以是任意的值,或者限制为枚举值。任何情况下,默认值都是必须要写的,当client没有提供值时,默认值就会生效。变量描述则是可选的。server模版通常的使用例子如下:
servers:
- url: http://api.example.com
- url: https://api.example.com
或
servers:
- url: '{protocol}://api.example.com'
variables:
protocol:
enum:
- http
- https
default: https
servers:
- url: https://{environment}.example.com/v2
variables:
environment:
default: api # Production server
enum:
- api # Production server
- api.dev # Development server
- api.staging # Staging server
servers:
- url: https://{region}.api.cognitive.microsoft.com
variables:
region:
default: westus
enum:
- westus
- eastus2
- westcentralus
- westeurope
- southeastasia
servers:
- url: '{server}/v1'
variables:
server:
default: https://api.example.com # SaaS server
全局servers可以被path或者操作方法部分定义的servers进行覆盖,如下所示:
servers:
- url: https://api.example.com/v1
paths:
/files:
description: File upload and download operations
servers:
- url: https://files.example.com
description: Override base path for all operations with the /files path
...
/ping:
get:
servers:
- url: https://echo.example.com
description: Override base path for the GET /ping operation
这里主要指swagger提供的一系列工具,如编辑器,swagger UI等。
Swagger编辑器是用来编辑接口文档的小程序,简单易用。在官网上有在线版,当然也可以下载离线版来使用。下面通过在线版来看一下ui界面:
左侧就是符合openAPI规范的接口描述,右边是对应界面。具体的使用这里不详细介绍。
Swagger UI可以以网页的形式展示openAPI,其界面跟swagger editor展示的界面是一样的。
后端使用方式如下:
引入依赖包
<dependency>
<groupId>org.microprofile-ext.openapi-ext</groupId>
<artifactId>openapi-ui</artifactId>
<version>1.1.5</version>
</dependency>
或
<dependency>
<groupId>org.microprofile-ext.openapi-ext</groupId>
<artifactId>swagger-ui</artifactId>
<version>1.0.3</version>
</dependency>
这两个包其实是同一个东西,只是名字不同。
启动项目后,访问: http://localhost:8080/xxx/openapi-ui
接口,就能看到api页面了。其本质是先访问http://localhost:8080/openapi
接口,获得openAPI文档,然后通过ui插件 OpenApiUiService
进行渲染展示到页面上。更多信息可参见博主另一篇文章的API文档展示章节。
[1].https://swagger.io/docs/specification/about/