基本介绍
什么是OpenAPI
OpenAPI 规范(OAS),是定义一个标准的、与具体编程语言无关的RESTful API的规范。OpenAPI 规范使得人类和计算机都能在“不接触任何程序源代码和文档、不监控网络通信”的情况下理解一个服务的作用。如果您在定义您的 API 时做的很好,那么使用 API 的人就能非常轻松地理解您提供的 API 并与之交互了。
如果您遵循 OpenAPI 规范来定义您的 API,那么您就可以用文档生成工具来展示您的 API,用代码生成工具来自动生成各种编程语言的服务器端和客户端的代码,用自动测试工具进行测试等等。
什么是swagger
Swagger是一套基于OpenApi的开源工具套装,可用于对api文档进行设计、生成和使用。主要包括以下工具:
- Swagger Editor – 浏览器编辑器,可用于编辑OpenAPI说明.
- Swagger UI – 以API文档的方式提供OpenAPI说明书。
- Swagger Codegen - 根据OpenAPI文档生成服务端存根和客户端库。
为什么要使用OpenAPI?
OpenAPI的最根本的目的是为了描述接口本身。OpenAPI规范和Swagger工具通过多种方式来满足api开发的需要:
- 设计优先的用户: 使用Swagger Codegen来为api生成服务端存根代码,你唯一需要做的事就是实现业务逻辑。
- Swagger Codegen代码生成支持超过40种语言。
- Swagger UI可以用来生成API交互文档,使用者可以直接通过浏览器来进行api调用。
- 使用OpenAPI规范来连接其他的开发工具,例如可以将规范文档导入到SoapUI中来自动生成测试用例。
- 当然还有其他很多特性,可以通过开源代码和swagger中集成的商业化工具来探索。
基本结构
可以通过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
下面是一个openAPI文档根元素表格(出处)。
元数据
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: []
支持的鉴权方法有:
- HTTP鉴权: Basic, Bearer等。
- API key 作为请求头或者查询参数或者放在cookies里面
- OAuth 2
- OpenID Connect Discovery
认证和授权
OpenAPI 3.0 允许你通过以下的security schemes来描述受保护的api:
- HTTP 认证机制 (主要使用于Authorization header):
(1)Basic
(2)Bearer - RFC 7235 中定义的其他HTTP机制和HTTP Authentication Scheme Registry
- 请求头,查询字符串或者cookies里面的API keys
- OAuth 2
- OpenID Connect Discovery
OpenAPI 2.0到OpenAPI 3.0的变化
如果你之前使用了OpenAPI 2.0, 那么你可以从以下几个方面获取到OpenAPI 3.0在安全认证方面的变化:
-
securityDefinitions
变更为securitySchemes
,并且移到了components
元素里面。 -
type: basic
变更为type: http
和scheme: basic
和组合。 - 新增的
type: http
是所有的HTTP安全模式的总体类型,包括Basic
,Bearer
和其他,而且scheme关键字就能表明机制的类型。 - API keys现在可以放到cookie里面。
- 增加了对OpenID Connect Discovery (type: openIdConnect)的支持。
- OAuth 2 机制现在可以定义多种流程。
- OAuth 2 流程被重新命名,以适配OAuth 2 规范:
accessCode
变更为authorizationCode
,application
变更为clientCredentials
。
安全描述
关键字securitySchemes
和 security
用来描述安全性。你可以使用securitySchemes
来定义API接口的安全机制,并使用security
来为所有API或者某个操作申请具体的机制。
Step 1. 定义securitySchemes
先定义,再使用。也就是说必须先在components/securitySchemes部分定义安全机制,之后才能在API中去使用。以下就是所谓的安全机制类型和安全机制(securitySchemes):
- http – Basic, Bearer 和其他 HTTP 认证机制
- apiKey – API keys and cookie authentication
- oauth2 – OAuth 2
- openIdConnect – OpenID Connect Discovery
每种安全机制所需的其他属性取决于其类型。以下是一些例子:
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
Step 2. 应用安全性
声明了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: []
- 在 OAuth 2 的情况下,使用的范围必须事先在securitySchemes中定义。
- 对于 OpenID Connect Discovery,发现端列出的可能的范围通过openIdConnectUrl指定。
- 其他机制(Basic、Bearer、API 密钥等)不使用范围,因此它们的security条目指定一个空数组[]。
API Server和基本路径
API Server和Base URL
上文就提到过,所有的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格式
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模板
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模版通常的使用例子如下:
- 基于多种协议 (比如 as HTTP vs HTTPS)
servers:
- url: http://api.example.com
- url: https://api.example.com
或
servers:
- url: '{protocol}://api.example.com'
variables:
protocol:
enum:
- http
- https
default: https
- 基于多域名的,每一个server都有子域名,如:
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
- 基于地理位置的不同的区域server (比如亚马逊web服务)
servers:
- url: https://{region}.api.cognitive.microsoft.com
variables:
region:
default: westus
enum:
- westus
- eastus2
- westcentralus
- westeurope
- southeastasia
- Single API definition for SaaS and on-premise APIs.
servers:
- url: '{server}/v1'
variables:
server:
default: https://api.example.com # SaaS server
覆写Servers
全局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 Editor
Swagger编辑器是用来编辑接口文档的小程序,简单易用。在官网上有在线版,当然也可以下载离线版来使用。下面通过在线版来看一下ui界面:
左侧就是符合openAPI规范的接口描述,右边是对应界面。具体的使用这里不详细介绍。
Swagger UI
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>
这两个包其实是同一个东西,只是名字不同。