RESTful API 设计规范介绍
RESTful 是目前流行的 API 设计规范,遵守这套规范设计出的 API 可以较好的适用不同类型的客户端,例如:PC/Mobile/Pad…
RESTful 表现层状态转换(英语:Representational State Transfer,缩写:REST)是 Roy Thomas Fielding 博士于 2000 年在他的博士论文[1]中提出来的一种万维网软件架构风格,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息。
RESTFul 使用的协议
API 内容的传输总是基于HTTP 协议。 在线上产品通常使用安全的 HTTP 协议,即 HTTPS。
域名及 API 版本
如果这套 API 是提供第三方服务的,通常要用单独的域名。如果项目不专注于第三方服务或中小型项目可以在域名后加 api
来标识。
// 单独域名
http://api.domain.com
// 中小型项目,前后端共用域名
http://domain.com/api
版本号通常以 v1/v2 来标识,默认第一版不加路径中不加 v1,当接口有新版本后加版本标识,例如第二版 API 可以为:
http://api.domain.com/v2
http://domain.com/api/v2
如果只有部分接口出现第二版,如果第二版的 user 接口,通常只在 /users
后加版本号。
//之前版本
api/users/analysis
//第二版 analysis 接口
api/users/v2/analysis
路径 (Endpoint)
访问一个 API 要有一个确定的地址,这个地址即路径(Endpoint)。
在 RESTful 中每个路径都表示一个资源,这个资源可以是音视频、图片、文本(XML/JSON)。通常接口返回的是 JSON 数据,如一个用户的信息、一个用户列表。
接口的地址通常使用名词复数,表示这个资源的集合(Collection),例如关于用户的接口可能是这样的开头 /api/users
,关于图片相关的接口 /api/photos
,以上这些路径标识了这套 API 中某类资源。
在设计 RESTful API 时可以把这些路径想象为一个树形分支,可以把 api
当做根路径,之后的名词(users、photos)是跟节点(api)的分支,如果做成脑图它是这样的。
在操作系统中(win、unix、linux)文件都是按目录组织的,这些目录都是树型(在 unix/linux 及其明显),访问一个文件都是一个具体的目录加上一个文件名,API 接口区分不同资源也是这种方式。
集合中的某个对象的具体操作
常见 CRUD 操作通过 HTTP 动词区分,针对具体的某个对象操作在其集合(users、photos)加 id 然后在拼接上操作名称。
查询、修改某个用户(id:123)的信息。
// 123为用户id
GET /api/users/123
PUT /api/user/123
按照 process 本身的属性进行筛选对 process 进行筛选;获取 process 流程相关的表单相关的数据。
// 通常使用查询字符串(Query Param), 123为process记录(对象)的id
GET /api/processes/123?categories=1
// process的表单相关操作 - 获取其表单数据
GET /api/processes/123/form-data
// process的表单相关操作 - 删除其表单数据
DELETE /api/processes/123/form-data
// process的表单相关操作 - 对该表单数据进行分析操作
GET /api/processes/123/form-data/analysis
通过以上 API 路径可以形成如下树型脑图:
互联网公司是如何使用的
这里以 Github 为例,Github 开放 API 接口: https://api.github.com,下面是整理后的接口。
// 用户相关操作接口1 -- 用户其他信息
"current_user_url": "https://api.github.com/user",
"emails_url": "https://api.github.com/user/emails",
"followers_url": "https://api.github.com/user/followers",
"following_url": "https://api.github.com/user/following{/target}",
"keys_url": "https://api.github.com/user/keys",
"starred_url": "https://api.github.com/user/starred{/owner}{/repo}",
"user_org_url": "https://api.github.com/user/orgs",
"cur_user_repos_url": "https://api.github.com/user/repos{?type,page,per_page,sort}",
// 用户相关操作接口2 -- 对用户表相关的操作
"user_url": "https://api.github.com/users/{user}",
"user_repos_url": "https://api.github.com/users/{user}/repos{?type,page,per_page,sort}",
//搜索接口 -- 各种类别的搜索
"user_search_url": "https://api.github.com/search/users?q={query}{&page,per_page,sort,order}",
"code_search_url": "https://api.github.com/search/code?q={query}{&page,per_page,sort,order}",
"commit_search_url": "https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}",
"issue_search_url": "https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}",
"label_search_url": "https://api.github.com/search/labels?q={query}&repository_id={repository_id}{&page,per_page}",
"repos_search_url": "https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}",
// 组织操作接口
"org_url": "https://api.github.com/orgs/{org}",
"org_repos_url": "https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}",
"organization_teams_url": "https://api.github.com/orgs/{org}/teams"
总结:
- 使用路径变量(Path Value)使接口很有层次感
- 接口清晰易懂,一看就了解接口的作用
路径命令规范
- 通常常在路径中使用名词复数表示一类资源,如:users、photos
- 路径中的动词通常要变成名词,通常可在动词后加
ing
,如:api/processes/publishing - 如果路径中存在多个单词,中间使用 “-” 号分隔,如:api/processes/123/form-data
- 避免多级 URL,不利于扩展
- bad:
GET api/users/123/type/2
- good:
GET api/users/123?type=2
- bad:
错误的路径命名:
- /user/getAllUsers
- /user/createNewUser
- /user/deleteUser
HTTP 动词
RESTful API 的一大特点是使用 HTTP 动词来区分资源集合(users,photos,departments)的 CRUD,并且有不同的状态码,
这些是常用的动词。
- GET 请求用于查询(Read)
- POST 请求用于新增(Create)
- PUT 请求用于修改(Update)
- DELETE 请求用于删除(Delete)
- PATCH 更新(Update),通常是部分更新,不常用
动词返回状态码
这些返回值,与 200
状态码的含义密切相关。
虽然 201
204
都表示成功,但开发业务中通常都用 200
这个状态码表示。
- GET: 200 OK
- POST: 201 Created
- PUT: 200 OK
- DELETE: 204 No Content
- PATCH: 200 OK
状态码
客户端每次请求,服务器都必须给出响应。响应分为两个部分:状态码和数据。
每次响应应严格遵守 HTTP 状态码,这样便于服务端和浏览器的交互。
状态码分类:
- 1xx:相关信息
- 2xx:操作成功
- 3xx:重定向
- 4xx:客户端错误
- 5xx:服务器错误
业务中常用状态码
状态码(status) | 说明 | 备注 |
---|---|---|
200 | 正常 | |
401 | 未登录 | |
403 | 权限不足 | |
404 | 访问资源不存在 | |
500 | 不可控的服务器异常 | 可控制的业务逻辑异常使用 code 代表 |
服务端响应
服务端响应另一部分是数据。数据可是 xml、json 格式,如果是图片、视频文件在响应体中是二进制数据。
通常在 RESTful API 接口是以 JSON 格式数据交互的,因此客户端 HTTP 的请求头(header)中应携带 Accept
为 application/json
,同时服务端响应应携带 Content-Type
为 application/json
。下面是一个例子。
// Rquest
GET /api/user/123 HTTP/1.1
Accept: application/json
// Response
HTTP/1.1 200 OK
{
"code":200,
"message":"OK",
"data":{}
}
服务端响应体封装
因为业务的复杂性,HTTP 状态码并不能完全标识特殊业务信息,因此在业务响应体中通常带有 code
标识业务状态码,业务状态码基于 HTTP 状态码扩展。
常见的响应体封装如下:
{
"code":200,
"message":"OK",
"data":{}
}
服务端提供接口使用信息
API 的使用者未必知道,URL 是怎么设计的。一个解决方法就是,在回应中,给出相关链接,便于下一步操作。这样的话,用户只要记住一个 URL,就可以发现其他的 URL。这种方法叫做 HATEOAS。
api.github.com 就是一个很好的实践。用户只要访问这个接口就可得到接口信息。
一些实践
- 如果一个接口返回数据包含一组图片或视频,那么这些数据应该以完整的 URL 形式返回,而不是只有名字
- 一个好用的 API 在抛出业务异常是通常给出这个错误异常的 QA 链接