为什么选择 RESTful

我认为一套接口应该尽量满足以下几个原则:

  • 安全可靠,高效,易扩展。
  • 简单明了,可读性强,没有歧义。
  • API 风格统一,调用规则,传入参数和返回数据有统一的标准。

我们当然可以根据自己的经验,或者参考知名公司的接口总结设计出一套满足要求的接口,但是每个人对接口的理解不同,设计出来的接口也会有所不同,接口的命名,请求参数的格式,响应的结果,错误响应的错误码,等等很多地方都会有不一样的实现。当你去寻求一种设计理念来帮助我们设计出满足要求的接口,一定会发现 RESTful。
RESTful 的设计理念基于 HTTP 协议,因为 Roy Fielding 就是 HTTP 协议(1.0版和1.1版)的主要设计者。它是一种设计风格,没有规定我们一定如何实现,但是为我们提供了很好的设计理念。风格的统一,使得我们不需要过多的解释,就能让使用者明白该如何使用,同时也会有很多现成的工具来帮助我们实现 RESTful 风格的接口。

RESTful 设计原则

1. HTTPS

HTTPS 为接口的安全提供了保障,可以有效防止通信被窃听和篡改。而且现在部署 HTTPS 的成本也越来越低,你可以通过 cerbot 等工具,方便快速的制作免费的安全证书,所以生产环境,请务必使用 HTTPS。

另外注意,非 HTTPS 的 API 调用,不要重定向到 HTTPS,而要直接返回调用错误以禁止不安全的调用。

2. domian

应当尽可能的将 API 与其主域名区分开,可以使用专用的域名,访问我们的 API

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

例如:
https://api.vxndy.com

或者可以放在主域名下,例如:
https://www.vxndy.com/api

3. Version

随着业务的发展,需求的不断变化,API 的迭代是必然的,很可能当前版本正在使用,而我们就得开发甚至上线一个不兼容的新版本,为了让旧用户可以正常使用,为了保证开发的顺利进行,我们需要控制好 API 的版本。

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

通常情况下,有两种做法:

  • 将版本号直接加入 URL 中
https://api.vxndy.com/v1
https://api.vxndy.com/v2
  • 使用 HTTP 请求头的 Accept 字段进行区分
https://api.larabbs.com/
Accept: application/prs.vxndy.v1+json
Accept: application/prs.vxndy.v2+json

Github Api 虽然默认使用了第一种方法,但是其实是推荐并实现了第二种方法的,我们同样也尽量使用第二种方式。

4. Endpoints

在 RESTful 的架构中,所有的一切都表示资源,每一个 URL 都代表着一种资源,资源应当是一个名词,而且大部分情况下是名词的复数,尽量不要在 URL 中出现动词。
端点就是指向特定资源或资源集合的 URL。在端点的设计中,你 必须 遵守下列约定:

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

来看一个反例

再来看一个正列

5.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}从某个动物园解雇一名员工

6.Filtering

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

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

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

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

GET /trades?status=closed&sort=sortby=name&order=asc

# 可为其定制快捷方式
GET /trades/recently_closed

7.Authentication

应该 使用 OAuth2.0 的方式为 API 调用者提供登录认证。必须 先通过登录接口获取 Access Token 后再通过该 token 调用需要身份认证的 API

Oauth 的端点设计示列

  • RFC 6749 /token
  • Twitter /oauth2/token
  • Fackbook /oauth/access_token
  • Google /o/oauth2/token
  • Github /login/oauth/access_token
  • Instagram /oauth/authorize

客户端在获得 access token 的同时 必须 在响应中包含一个名为 expires_in 的数据,它表示当前获得的 token 会在多少 后失效。

{
    "access_token": "token....",
    "token_type": "Bearer",
    "expires_in": 3600
}

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

Authorization: Bearer token...

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

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
    "error": "invalid_token"
}

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

响应规范

restful 接口返回遵循统一格式, 设计参考类 Optional 遵循函数式编程规范

普通格式

{
  "data": "waht",
  "msg": null,
  "state": 1,
  "is_redirect": true,
  "redirect_url": "http://baidu.com",
  "token": null
}

带页码的格式

{
  "data": {
    "list": null,
    "pagebar": {
      "page": 1,
      "total": 2,
      "limit": 10
    }
  },
  "msg": "error",
  "state": 0,
  "is_redirect": true,
  "redirect_url": "http://qq.com",
  "token": null
}

参考资料
https://developer.github.com/v3/

https://developer.github.com/v3/guides/traversing-with-pagination/

标签: restful api, rest, api, laravel

添加新评论