api设计 - oceanbei333/leetcode GitHub Wiki

背景

在前后端分离以及微服务的趋势下,前后端以及微服务之间都需要通过接口进行通信,那么api就非常的重要了

痛点

  1. 接口规范问题,各个团队开发出来的各个服务的接口是否符合统一的接口规范
  2. 接口文档的版本管理
  3. 统一的地方去看接暴露出来的接口
  4. 接口的调试

api设计原则

Restful

  • URI

    • API与用户的通信协议,总是使用HTTPs协议。
    • 应该尽量将API部署在专用域名之下。
    • 应该将API的版本号放入URL。
    • 每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。
    • 避免层级过深的URI,尽可能短小
    • 用复数
  • Request

    • 对于资源的具体操作类型,由HTTP动词表示。

      • GET(SELECT):从服务器取出资源(一项或多项)。

        • 过于复杂的查询是否一定要用get方法
          
          {"role": "admin", "firstName": "Alex"}
          
          当请求的参数较多的时候
          
          1. 参数序列化\转义 /users?id[role]=admin&id[firstName]=Alex
          1. 使用路径参数
          2.  先使用post方法创建查询对象,再使用查询对象使用get方法获取
          3.  改为post方法,参数放到body中
          
      • POST(CREATE):在服务器新建一个资源。

      • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。

      • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。

      • DELETE(DELETE):从服务器删除资源。

    • 幂等性, 幂等性:执行1次和执行N次,对资源状态改变的效果是等价的。

    • 复杂查询查询可以捎带以下参数:

      • ?start_date=2020-01-01:指定开始日期过滤
      • ?pi=2&ps=100:指定第几页,以及每页的记录数。
      • ?sort=name.descend:指定返回结果按照哪个属性排序,以及排序顺序descend|ascend。
      • ?animal_type_id=1:指定筛选条件
      • ?search=1.1.1.1: 搜索关键字
    • 经常使用的、复杂的查询标签化,降低维护成本。

      GET /trades?status=closed&sort=created,desc

      GET /trades#recently-closed 或者 GET /trades/recently-closed

  • Response

    • response 的 body 直接就是数据,不要做多余的包装。
    • 正确设置http状态码,不要自定义状态码(Status Codes)
      • 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
      • 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
      • 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
      • 204 NO CONTENT - [DELETE]:用户删除数据成功。
      • 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
      • 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
      • 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
      • 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
      • 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
      • 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
      • 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
      • 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
  • 错误处理

    • 不要发生了错误但给2xx响应,客户端可能会缓存成功的http请求;

    • (Error handling),如果状态码是4xx,就应该向用户返回出错信息。

    • 错误格式

    • {
          "detail": "Given token not valid for any token type",
          "code": "token_not_valid",
          "messages": [
              {
                  "token_class": "AccessToken",
                  "token_type": "access",
                  "message": "Token is invalid or expired"
              }
          ]
      }
      
    • 针对不同操作,服务器向用户返回的结果应该符合以下规范。

      • GET /collection:返回资源对象的列表(数组)
      • GET /collection/resource:返回单个资源对象
      • POST /collection:返回新生成的资源对象
      • PUT /collection/resource:返回完整的资源对象
      • PATCH /collection/resource:返回完整的资源对象
      • DELETE /collection/resource:返回一个空文档
  • 服务型资源

    除了资源简单的CRUD,服务器端经常还会提供其他服务,这些服务无法直接用上面提到的URI映射。如:

    1. 按关键字搜索;
    2. 计算地球上两点间的距离;
    3. 批量向用户推送消息

    可以把这些服务看成资源,计算的结果是资源的presentation,按服务属性选择合适的HTTP方法。

    GET /search?q=filter?category=file  搜索
    GET /distance-calc?lats=47.480&lngs=-122.389&late=37.108&lnge=-122.448
    POST /batch-publish-msg
    [{"from":0,"to":1,"text":"abc"},{},{}...]
    
  • 异步任务

    对耗时的异步任务,服务器端接受客户端传递的参数后,应返回创建成功的任务资源,其中包含了任务的执行状态。客户端可以轮训该任务获得最新的执行进度。

    提交任务:
    POST /batch-publish-msg
    [{"from":0,"to":1,"text":"abc"},{},{}...]
    
    返回:
    {"taskId":3,"createBy":"Anonymous","status":"running"}
    
    GET /task/3
    {"taskId":3,"createBy":"Anonymous","status":"success"}
    
    

openapi

Open API 规范(OpenAPI Specification,是REST API 的 API 描述格式。

swagger

Swagger 是一套围绕 Open API 规范构建的开源工具,可以帮助设 计,构建,记录和使用 REST API。

  1. Swagger Editor :基于浏览器编辑器,可以在里面编写 Open API规范。类似 Markdown 具有实时预览描述文件的功能。
  2. Swagger UI:将 Open API 规范呈现为交互式 API 文档。用可视化UI 展示描述文件。也可以对接口进行调试
  3. Swagger Codegen:将 OpenAPI 规范生成为服务器存根和客户端 库。通过 Swagger Codegen 可以将描述文件生成 html 格式和 cwiki 形 式的接口文档,同时也可以生成多种言语的客户端和服务端代码。
  4. Swagger Inspector:和 Swagger UI 有点类似,但是可以返回更多 信息,也会保存请求的实际参数数据。
  5. Swagger Hub:集成了上面所有项目的各个功能,你可以以项目 和版本为单位,将你的描述文件上传到 Swagger Hub 中。在 Swagger Hub 中可以完成上面项目的所有工作,需要注册账号,分免费版和收费版。  

使用 Swagger,就是把相关的信息存储在它定义的描述文件里面(yml 或 json 格式),再通过维护这个描述文件可以去更新接口文档, 以及生成各端代码。

openapi

OpenAPI文档部分或对象:

  1. Metadata - OpenAPI规范版本的语义版本号等信息
  2. Servers he API server and base URL.
  3. paths - API的可用路径和操作
  4. Components- 一些模型定义、认证相关
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: 
                $ref: '#/components/schemas/User'
 components:
  schemas:
    User:
      properties:
        id:
          type: integer
        name:
          type: string
      # Both properties are required
      required:  
        - id
        - name

1. Metadata

the version of the OpenAPI

openapi: 3.0.0

The info section contains API information

info:
  title: Sample API
  description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
  version: 0.1.9

2. Servers

the API server and base URL.

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

3. Paths

individual endpoints (paths) in your API, and the HTTP methods

paths:
  /users:
    get:
      summary: Returns a list of users.
      description: Optional extended description in CommonMark or HTML
      responses:
        '200':
          description: A JSON array of user names
          content:
            application/json:
              schema: 
                type: array
                items: 
                  type: string
  1. Parameters

http method can have parameters passed via URL path (/users/{userId}), query string (/users?role=admin), headers (X-CustomHeader: Value) or cookies (Cookie: debug=0).

paths:
  /user/{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
  • path parameters, such as /users/{id}

    paths:
      /users/{id}:
        get:
          parameters:
            - in: path
              name: id   # Note the name is the same as in the path
              required: true
              schema:
                type: integer
                minimum: 1
              description: The user ID
    
  • query parameters, such as /users?role=admin

         parameters:
            - in: query
              name: offset
              schema:
                type: integer
              description: The number of items to skip before starting to collect the result set
            - in: query
              name: limit
              schema:
                type: integer
              description: The numbers of items to return
    
  • header parameters, such as X-MyHeader: Value

    paths:
      /ping:
        get:
          summary: Checks if the server is alive
          parameters:
            - in: header
              name: X-Request-ID
              schema:
                type: string
                format: uuid
              required: true
    
  • cookie parameters, which are passed in the Cookie header, such as Cookie: debug=0; csrftoken=BUSe35dohU3O1MZvDCU

          parameters:
            - in: cookie
              name: debug
              schema:
                type: integer
                enum: [0, 1]
                default: 0
            - in: cookie
              name: csrftoken
              schema:
                type: string
    
  1. Request Body
paths:
  /users:
    post:
      summary: Creates a user.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                username:
                  type: string
      responses: 
        '201':
          description: Created
  1. Responses
paths:
  /user/{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

4. Components Section

the global components/schemas section lets you define common data structures used in your API.

{
  "id": 4,
  "name": "Arthur Dent"
}
components:
  schemas:
    User:
      properties:
        id:
          type: integer
        name:
          type: string
      # Both properties are required
      required:  
        - id
        - name

数据类型

  • string (this includes dates and files)

    • String Formats

      • date – full-date notation as defined by RFC 3339, section 5.6, for example, 2017-07-21
      • date-time – the date-time notation as defined by RFC 3339, section 5.6, for example, 2017-07-21T17:32:28Z
      • password – a hint to UIs to mask the input
      • byte – base64-encoded characters, for example, U3dhZ2dlciByb2Nrcw==
      • binary – binary data, used to describe files (see Files below)
      • Ipv4
    • pattern

    • Enums

    type: string
    nullable: true  # <---
    enum:
      - asc
      - desc
      - null  
    
  • number

  • integer

  • boolean

  • array

    type: array
    items:
      type: string
    
  • object

    type: object
    properties:
      id:
        type: integer
      name:
        type: string
    required:
      - id
    
    

    Authentication and Authorization

    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
    

drf-yasg

Generate real Swagger/OpenAPI 2.0 specifications from a Django Rest Framework API.

功能

  1. 自动生成DRF的基于类的接口文档
  2. Swagger Codegen
  3. swagger ui
  4. redoc

使用

@swagger_auto_schema

  1. method

  2. manual_parameters openapi.Parameter

    1. 位置参数-IN_QUERY
    2. 请求体-IN_BODY
  3. responses

    Schema

与json的映射关系

  1. 字典-TYPE_OBJECT
  2. 列表-TYPE_ARRAY
  3. 字符串-TYPE_STRING
  4. 布尔-TYPE_BOOLEAN

实践

swagger ediit

方便修改文档以及文档的导出

make start-swagger-editor

Swagger ui

查看文档

默认展示diting.yaml

make start-swagger-ui

Jenkins

修改文档之后,会自动触发jenkins的任务,更新文档