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=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 asCookie: debug=0; csrftoken=BUSe35dohU3O1MZvDCU
parameters: - 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: - 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.
功能
- 自动生成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的任务,更新文档