REST API 设计原则
REST API 的设计很有讲究,我司总结了一些规范和原则,详见 Cisco REST API 规范,编译如下:
REST 方法
- GET 方法的响应是由所请求URL代表的资源的表示
- GET 方法不会改变请求URL所代表的资源
- POST 请求在所请求的URL 路径下创建一个新的资源以作为叶子节点
- POST 响应体或者为空(响应状态码为204), 或者是所创建的资源的表示(响应状态码为201)
- PUT 请求一个URL, 如果没有相应的资源存在, 就会创建一个相应的新资源
- PUT 请求一个URL, 如果已经有相应的资源存在, 就会以请求体中的内容覆盖这个资源
- PUT 响应体是所请求的URL代表的资源的表示, 包含了这个请求所作出的修改
- DELETE 请求一个URL, 会删除相应的已存在的资源
- DELETE 的响应体或者为空(响应码为204) , 或者是资源的表示(响应码为200)
- PATCH 请求一个URL, 是部分地修改相应的资源的状态, 参见 RFC6902
- PATCH 响应返回所请求的URL代表的资源的表示, 包含了这个请求所作出的修改
URL 路径
- URL 路径表示一个资源, 或一组资源的集合
- URL 路径的开头形式一般为 /{service}/{apiclass}/v{version}
- 集合 URL 的最后一段是一个名词算数, 描述所包含资源的类型
- 资源 URL 路径的最后一段的父节点是复数名词,表示资源集合。
- 资源 URL 路径的最后一段是其容器内资源的唯一标识符。
- URL 路径各段是字母或者数字,遵循驼峰命名法的约定(第一个字符是小写)
- URL 路径各段的命名要直观,明确,简洁, 既不拖沓, 又一目了然
URL 查询参数
- 表示日期/时间的URL查询参数采用 RFC-3339 的 iso-date-time 格式
- 表示持续时间的URL查询参数采用 RFC-3339 的 duration 格式
- 表示时间间隔的URL查询参数采用 RFC-3339 的 period 格式
- URL查询参数在语义上以及在API中其他位置同名的参数要保持统一
- 如果选择所查询资源的特定字段, URL查询参数要符合字段命名和标准规范. 比如: ?fields=subject,body,createTime
- 与分页检索有关的URL查询参数符合分页查询形式: ?page=1&size=20&sort=username,asc
- URL查询参数名称是字母数字,并遵循驼峰命名法的约定(第一个字符是小写)
- URL查询参数名称应该直观,明确,简洁。
Resource Representations 资源表示
- 资源的表示通常编码为 application/json, 除非资源为其他标准的多媒体类型, 比如 png, vcard 等等
- 资源的集合通常编码为 application/json, 集合以 json 数组形式给出
- 如果一个集合支持分页, 那么这个集合的表示应该包括一些标准的分页属性, 比如集合放在 results 数组中, 加上 start(开始), size(页长), total(总数)等属性, 还可以包含一个 _links 对象, 包括 first, prev, next, last, self 这些链接作为属性
- 一个资源推荐在资源查询的响应中提供一个 url 属性, 表示这个资源自己的链接
- 一个资源不推荐包含另一个服务所拥有和负责的资源, 可以给出一个资源的链接, 使用绝对路径和规范的 URL 形式
- 在资源的响应体中一般不包括状态信息, 以免和本身http status code 发生语义上的不一致
- 在返回一个 4xx 或 5xx 的 HTTP 响应码时, 响应主体中就包括标准的错误信息, 比如: errorCode, errorReason, errorMessage等
JSON Attributes
- 属性名称直观,明确,简洁。
- 属性名称是字母数字,遵循camelCase约定(第一个字符是小写)。
- 表示日期/时间的属性采用RFC-3339 iso-date-time格式,并具有UTC偏移量。
- 表示持续时间的属性采用RFC-3339持续时间格式。
- 表示时间间隔的属性采用RFC-3339周期格式。
- 表示二进制值的属性使用JSON本机布尔类型进行编码。
- 表示数组的属性被命名为复数名词。
- 表示非数组的属性被命名为单数名词。
- 表示其他资源链接的属性以绝对和规范URL 的形式提供。
- 属性名称在各个地方应该在保持统一的语义
- 表示枚举类型的属性要具有明确定义的合法值和语义。
- 缺少JSON属性与显式赋值为null之间没有语义上的区别。
Security
- REST 请求必需使用 OAuth2 之类的协议进行身份验证,授权
- REST 请求具有关于访问所需资源的要有明确的授权策略。
- 必须验证包含个人身份信息(PII)的REST请求。
- REST请求不允许用户之间无意的内容或PII泄漏。
- 必须通过安全通道(HTTPS)进行身份验证的 REST 请求。
- REST请求不可以在URL中包含身份验证,授权或 PII 信息。
API Documentation
- API 文档应该由源代码或注释自动生成, 比如 swagger 之类的
- 自动生成的文档应该对于资源和所提供方法提供足够的描述信息
- 自动生成的文档应该对于认证,授权策略及调用方法提供足够的描述信息
- 自动生成的文档应该对于URL 路径, 调用参数等提供足够的描述信息
- 自动生成的文档应该对于表示资源的 JSON 属性提供足够的描述信息
- 自动生成的文档应该对于预计的错误触发条件和响应码提供足够的描述信息
API 文档工具
API 文档的生成有很多框架和工具, 现在比较流行的有三种:
1) RESTful API Modeling Language (RAML)
顾名思义, 它是一个RESTful API 的建模语言, 好象UML 类图那样, 通过这个建模语言描述的 raml 文件来定义你的 API 格式, 然后通过工具(raml2html)来生成易读的HTML 文档, 你需要手动编写 raml 文件, 然后生成所需文档.
它已经形成了一套规范和工具, 例如
• API Workbench: 一个功能完善的IDE, 可用来设计, 构建,测试 RESTful API, 和相应文档生成和分享
• RAML Java Client Generator: 一个可以基于 RAML 文档自动生成Java 客户端代码的工具
• RAML2HTML: 一个Node.js 工具, 将 RAML 文件转化成易于阅读的 HTML文档.
例如以如下 raml 来定义API
#%RAML 1.0
title: Hello world # required title
version: 1
baseUri: http://example.com/{version}
documentation:
- title: Welcome
content: |
Welcome to the Example Documentation. The Example API allows you
to do stuff. See also [example.com](https://www.example.com).
- title: Chapter two
content: |
More content here. Including **bold** text!
/helloworld: # optional resource
description: This is the top level description for /helloworld.
get: # HTTP method declaration
responses: # declare a response
200: # HTTP status code
body: # declare content of response
application/json: # media type
type: | # structural definition of a response (schema or type)
{
"title": "Hello world Response",
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
example: # example how a response looks like
{
"message": "Hello world"
}
/test:
displayName: TEST
get:
description: a sub resource
/{id}:
uriParameters:
id:
type: string
description: account identifier
minLength: 1
maxLength: 10
get:
headers:
Authorization:
type: string
description: Basic authentication header
example: |
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
put:
body:
application/x-www-form-urlencoded:
properties:
name:
description: name on account
type: string
examples:
example1: Naruto Uzumaki
example2: Kevin Renskers
gender:
enum: ["male", "female"]
然后安装 raml2html
npm i -g raml2html
npm i -g raml2html-markdown-theme
- 执行
raml2html api.raml > api.html
生成的 API html 文件如下
详情参见 https://github.com/raml2html/raml2html
2) Swagger UI
它是一个更加流行的文档生成框架, 强调从代码中全自动生成 API 文档
这个框架有三个主要的组件:
• Swagger 是它的规范部分, 一套描述 RESTful 服务的规则, 类似于 RAML
• Swagger UI 是它的渲染部分, 它就象 RAML2HTML 那样生成易读的HTML文档, 用户无需用任何客户端就可基于Swagger 规范用它自动生成的客户端进行API测试
• Springfox 是它的生成部分, 通过Java代码, SpringMVC 和 Swagger 的注解来自动生成API 文档.
3) Spring REST Docs
这是 Spring 生态圈, 它基于API 测试来生成 AsciiDoc 文档, 你也可以自己编写一些描述性的 AsciiDoc 文档, 这些 AsciiDoc 文档可以通过它提供的 maven 插件自动生成易读的 HTML 文档, 相比前两者, 它介于手动和全自动之间, 相当于半自动的工具.
如果你是一个新项目, 在设计阶段就可以采用 RAML 来定义你的 API, 如果是老项目, 采用 Swagger 会更省力, 当然 Spring REST Docs 更加符合测试驱动开发的理念, 既可以通过测试来自动生成文档, 也可以手动添加说明, 推荐使用