api设计 - oceanbei333/leetcode GitHub Wiki
背景
在前后端分离以及微服务的趋势下,前后端以及微服务之间都需要通过接口进行通信,那么api就非常的重要了
痛点
- 接口规范问题,各个团队开发出来的各个服务的接口是否符合统一的接口规范
 - 接口文档的版本管理
 - 统一的地方去看接暴露出来的接口
 - 接口的调试
 
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映射。如:
- 按关键字搜索;
 - 计算地球上两点间的距离;
 - 批量向用户推送消息
 
可以把这些服务看成资源,计算的结果是资源的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。
- Swagger Editor :基于浏览器编辑器,可以在里面编写 Open API规范。类似 Markdown 具有实时预览描述文件的功能。
 - Swagger UI:将 Open API 规范呈现为交互式 API 文档。用可视化UI 展示描述文件。也可以对接口进行调试
 - Swagger Codegen:将 OpenAPI 规范生成为服务器存根和客户端 库。通过 Swagger Codegen 可以将描述文件生成 html 格式和 cwiki 形 式的接口文档,同时也可以生成多种言语的客户端和服务端代码。
 - Swagger Inspector:和 Swagger UI 有点类似,但是可以返回更多 信息,也会保存请求的实际参数数据。
 - Swagger Hub:集成了上面所有项目的各个功能,你可以以项目 和版本为单位,将你的描述文件上传到 Swagger Hub 中。在 Swagger Hub 中可以完成上面项目的所有工作,需要注册账号,分免费版和收费版。
 
使用 Swagger,就是把相关的信息存储在它定义的描述文件里面(yml 或 json 格式),再通过维护这个描述文件可以去更新接口文档, 以及生成各端代码。
openapi
OpenAPI文档部分或对象:
- Metadata - OpenAPI规范版本的语义版本号等信息
 - Servers he API server and base URL.
 - paths - API的可用路径和操作
 - 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
- 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=adminparameters: - 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: Valuepaths: /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
Cookieheader, such asCookie: debug=0; csrftoken=BUSe35dohU3O1MZvDCUparameters: - in: cookie name: debug schema: type: integer enum: [0, 1] default: 0 - in: cookie name: csrftoken schema: type: string 
- 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
- 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-21date-time– the date-time notation as defined by RFC 3339, section 5.6, for example, 2017-07-21T17:32:28Zpassword– a hint to UIs to mask the inputbyte– 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 - 
 - 
type: array items: type: string - 
type: object properties: id: type: integer name: type: string required: - idAuthentication 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.
功能
- 自动生成DRF的基于类的接口文档
 - Swagger Codegen
 - swagger ui
 - redoc
 
使用
@swagger_auto_schema
- 
method
 - 
manual_parameters openapi.Parameter
- 位置参数-IN_QUERY
 - 请求体-IN_BODY
 
 - 
responses
Schema
 
与json的映射关系
- 字典-TYPE_OBJECT
 - 列表-TYPE_ARRAY
 - 字符串-TYPE_STRING
 - 布尔-TYPE_BOOLEAN
 
实践
swagger ediit
方便修改文档以及文档的导出
make start-swagger-editor
Swagger ui
查看文档
默认展示diting.yaml
make start-swagger-ui
Jenkins
修改文档之后,会自动触发jenkins的任务,更新文档