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)的分支,如果做成脑图它是这样的。

image.png

在操作系统中(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 路径可以形成如下树型脑图:

image.png

互联网公司是如何使用的

这里以 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

错误的路径命名:

  • /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:服务器错误

详细 HTTP 状态码

业务中常用状态码
状态码(status) 说明 备注
200 正常
401 未登录
403 权限不足
404 访问资源不存在
500 不可控的服务器异常 可控制的业务逻辑异常使用 code 代表

服务端响应

服务端响应另一部分是数据。数据可是 xml、json 格式,如果是图片、视频文件在响应体中是二进制数据。

通常在 RESTful API 接口是以 JSON 格式数据交互的,因此客户端 HTTP 的请求头(header)中应携带 Acceptapplication/json,同时服务端响应应携带 Content-Typeapplication/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 链接

参考资料、其他资料