基本介绍

什么是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文档根元素表格(出处)。

openapi架构图 openapi开发框架_HTTP

元数据

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:

OpenAPI 2.0到OpenAPI 3.0的变化

如果你之前使用了OpenAPI 2.0, 那么你可以从以下几个方面获取到OpenAPI 3.0在安全认证方面的变化:

  • securityDefinitions变更为securitySchemes,并且移到了components元素里面。
  • type: basic 变更为 type: httpscheme: basic和组合。
  • 新增的type: http是所有的HTTP安全模式的总体类型,包括 Basic, Bearer 和其他,而且scheme关键字就能表明机制的类型。
  • API keys现在可以放到cookie里面。
  • 增加了对OpenID Connect Discovery (type: openIdConnect)的支持。
  • OAuth 2 机制现在可以定义多种流程。
  • OAuth 2 流程被重新命名,以适配OAuth 2 规范: accessCode变更为authorizationCodeapplication 变更为clientCredentials

安全描述

关键字securitySchemessecurity 用来描述安全性。你可以使用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架构图 openapi开发框架_API_02


在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架构图 openapi开发框架_openapi架构图_03

左侧就是符合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>

这两个包其实是同一个东西,只是名字不同。