RESETful API 设计规范

关于「能愿动词」的使用

为了避免歧义,文档大量使用了「能愿动词」,对应的解释如下:

  • 必须 (MUST):绝对,严格遵循,请照做,无条件遵守;
  • 一定不可 (MUST NOT):禁令,严令禁止;
  • 应该 (SHOULD):强烈建议这样做,但是不强求;
  • 不该 (SHOULD NOT: 强烈不建议这样做,但是不强求;
  • 可以 (MAY)可选 (OPTIONAL):选择性高一点,在这个文档内,此词语使用较少;

协议

在通过 API 于后端服务通信的过程中,应该 使用 HTTPS 协议。

API Root URL

API 的根入口点应尽可能保持足够简单,这里有两个常见的 URL 根例子:

  • api.example.com/*
  • example.com/api/*

如果你的应用很庞大或者你预计它将会变的很庞大,那 应该API 放到子域下。这种做法可以保持某些规模化上的灵活性。

Version

所有的 API 必须保持向后兼容,你 必须 在引入新版本 API 的同时确保旧版本 API 仍然可用。所以 应该 为其提供版本支持。

目前比较常见的两种版本号形式:

在 URL 中嵌入版本编号

api.example.com/v1/*

这种做法是版本号直观、易于调试;另一种做法是,将版本号放在 HTTP Header 头中:

通过媒体类型来指定版本信息

Accept: application/vnd.example.com.v1+json

其中 vnd 表示 Standards Tree 标准树类型,有三个不同的树: xprsvnd。你使用的标准树需要取决于你开发的项目

  • 未注册的树(x)主要表示本地和私有环境
  • 私有树(prs)主要表示没有商业发布的项目
  • 供应商树(vnd)主要表示公开发布的项目

后面几个参数依次为应用名称(一般为应用域名)、版本号、期望的返回格式。

至于具体把版本号放在什么地方,这个问题一直存在很大的争议,但由于我们大多数时间都在使用 Laravel 开发,应该 使用 dingo/api 来快速构建应用,它采用第二种方式来管理 API 版本,并且已集成了标准的 HTTP Response

Endpoints

端点就是指向特定资源或资源集合的 URL。在端点的设计中,你 必须 遵守下列约定:

  • URL 的命名 必须 全部小写
  • URL 中资源(resource)的命名 必须 是名词,并且 必须 是复数形式
  • 必须 优先使用 Restful 类型的 URL
  • URL 中不能出现 -必须 用下划线 _ 代替
  • URL 必须 是易读的
  • URL 一定不可 暴露服务器架构

来看一个反例:

  • https://api.example.com/getUserInfo?userid=1
  • https://api.example.com/getusers
  • https://api.example.com/sv/u
  • https://api.example.com/cgi-bin/users/get_user.php?userid=1

再来看一个正列:

  • https://api.example.com/zoos
  • https://api.example.com/animals
  • https://api.example.com/zoos/{zoo}/animals
  • https://api.example.com/animal_types
  • https://api.example.com/employees

HTTP 动词

对于资源的具体操作类型,由 HTTP 动词表示。常用的 HTTP 动词有下面五个(括号里是对应的 SQL 命令)。

  • GET(SELECT):从服务器取出资源(一项或多项)。
  • POST(CREATE):在服务器新建一个资源。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
  • DELETE(DELETE):从服务器删除资源。

其中

1 删除资源 必须 用 DELETE 方法
2 创建新的资源 必须 使用 POST 方法
3 更新资源 应该 使用 PUT 方法
4 获取资源信息 必须 使用 GET 方法

针对每一个端点来说,下面列出所有可行的 HTTP 动词和端点的组合

请求方法 URL 描述
GET /zoos 列出所有的动物园(ID和名称,不要太详细)
POST /zoos 新增一个新的动物园
GET /zoos/{zoo} 获取指定动物园详情
PUT /zoos/{zoo} 更新指定动物园(整个对象)
PATCH /zoos/{zoo} 更新动物园(部分对象)
DELETE /zoos/{zoo} 删除指定动物园
GET /zoos/{zoo}/animals 检索指定动物园下的动物列表(ID和名称,不要太详细)
GET /animals 列出所有动物(ID和名称)
POST /animals 新增新的动物
GET /animals/{animal} 获取指定的动物详情
PUT /animals/{animal} 更新指定的动物(整个对象)
PATCH /animals/{animal} 更新指定的动物(部分对象)
GET /animal_types 获取所有动物类型(ID和名称,不要太详细)
GET /animal_types/{type} 获取指定的动物类型详情
GET /employees 检索整个雇员列表
GET /employees/{employee} 检索指定特定的员工
GET /zoos/{zoo}/employees 检索在这个动物园工作的雇员的名单(身份证和姓名)
POST employees 新增指定新员工
POST /zoos/{zoo}/employees 在特定的动物园雇佣一名员工
DELETE /zoos/{zoo}/employees/{employee} 从某个动物园解雇一名员工

Filtering

如果记录数量很多,服务器不可能都将它们返回给用户。API 应该 提供参数,过滤返回结果。下面是一些常见的参数。

  • ?limit=10:指定返回记录的数量
  • ?offset=10:指定返回记录的开始位置。
  • ?page=2&per_page=100:指定第几页,以及每页的记录数。
  • ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
  • ?animal_type_id=1:指定筛选条件

所有 URL 参数 必须 是全小写,必须 使用下划线类型的参数形式。

经常使用的、复杂的查询 应该 标签化,降低维护成本。如

  1. GET /trades?status=closed&sort=sortby=name&order=asc
  2. # 可为其定制快捷方式
  3. GET /trades/recently_closed

Authentication

应该 使用 OAuth2.0 的方式为 API 调用者提供登录认证。必须 先通过登录接口获取 Access Token 后再通过该 token 调用需要身份认证的 API
客户端在获得 access token 的同时 必须 在响应中包含一个名为 expires_in 的数据,它表示当前获得的 token 会在多少 后失效。

  1. {
  2. "access_token": "token....",
  3. "token_type": "Bearer",
  4. "expires_in": 3600
  5. }

客户端在请求需要认证的 API 时,必须 在请求头 Authorization 中带上 access_token

  1. Authorization: Bearer token...

当超过指定的秒数后,access token 就会过期,再次用过期/或无效的 token 访问时,服务端 应该 返回 invalid_token 的错误或 401 错误码。

  1. HTTP/1.1 401 Unauthorized
  2. Content-Type: application/json
  3. Cache-Control: no-store
  4. Pragma: no-cache
  5. {
  6. "error": "invalid_token"
  7. }

Laravel 开发中,应该 使用 JWT 来为管理你的 Token,并且 一定不可api 中间件中开启请求 session



评论 0

发表评论

Top