分类

REST API 实践

2019-08-12 17:08 programming

REST API 用于表示服务器端的资源模型(resource model).

可以使用 WRML (Web Resource Modeling Language) 来设计及实现统一的 REST API.

URIs

RFC3986 定义的 URI 格式是:

URI = scheme "://" authority "/" path ["?" query ] [ "#" fragment ]

URI 的命名有以下规则:

斜杠分隔符 (/) 用来表明层级关系 (hierachical relationship)

使用斜杠来表明资源之间的层级关系. 比如:

https://consumer.example.com/shapes/polygons/squares

被斜杠分隔开的路径代表了在此层级关系中独特的资源.

结尾不应该包含斜杠

在结尾加上斜杠除了更混乱之外没有它用.

// 差
https://consumer.example.com/shapes/polygons/squares/
// 好
https://consumer.example.com/shapes/polygons/squares

单词之间可以使用连字符 (-)

使用连字符可以增加可读性:

https://consumer.example.com/machines/42/open-door

不应该使用下划线来分隔单词.

应使用小写字母

RFC3986 中规定, 除了 schemehostname 是大小写不敏感的之外, URI 中的其它部分都是区分大小写的.

为了免于混乱, 都应该使用小写字母.

结尾不应该包含扩展名

比如:

// 差
https://consumer.example.com/students/324381/records/42/fall.json
// 好
https://consumer.example.com/students/324381/records/42/fall

如果要指定该请求返回的媒体类型 (media type), 需要在 Http 响应头中写明 Content-Type.

请求方法

GET

用于获取资源.

用于获取资源的 HTTP 响应头, 其它与 GET 方法一致. 这个方法可以用于确认一个资源是否存在, 或者为了从 HTTP 响应头中读取 metadata

POST

用来创建新的资源:

POST /leagues/teams/players

也被用来执行该资源上绑定的函数:

POST /machines/42/open-door

PUT

用来更新资源, body 里面可以包含待更新的字段.

PUT/POST 都应该把创建或者更新后的资源返回.

DELETE

用于从上一级删除该资源.

Option

返回 metadata, 用于描述该资源支持的请求方法, 比如:

Allow: GET, PUT, DELETE

返回的状态码

  • 1xx, Informational, 传输层间的通信
  • 2xx, Success, 表示客户端的请求已被成功接受
  • 3xx, Redirection, 表示客户端需要采取额外的动作来完成请求
  • 4xx, Client Error, 表示客户端的有错误
  • 5xx, Server Error, 表示服务端处理请求时出现错误

200

表示客户端的请求成功被处理.

有这样一种让服务器端处理错误的方法:

  • http response status 是200
  • 在 response body 里面写上 { "error": 3, "erroMsg": "invalid username" }

这种方法, 可以让客户端只用一个函数就可以处理完返回的所有请求. 但是有几个缺陷:

  • 如果服务器端有 API 网关的话, 它是无法统计这种出错类型的
  • 如果客户端是运行在浏览器上的话, 它也无法感知错误
  • 网页前端目前会用 (successHandler, errorHandler) 这种方法来处理正确的返回以及错误.

201

表示一个新的资源被创建.

202

表求服务端已接受客户端的请求, 但需要异步处理该任务.

204

表示服务端返回的 response body 为空, 且有意为空.

301

表示一个资源被永久地重定向到新的位置了, 同时在 http 响应头里包含 Location, 来给出新的地址.

302

303

304

表示资源未经修改, 客户端依然可以使用本地缓存了的.

307

表示资源被临时重定向到别处.

400

表示客户端请求有误, 比如缺少了某些必要的参数.

401

表示未经授权的访问.

403

表示当前客户端提供的授权凭证无权限访问该资源.

404

这个最为常见, 表示该资源找不到.

405

406

409

412

415

500

服务器内部错误, 比如后台代码本身出问题.

502

服务端访问别的资源时出错, 比如数据库下线了.

Http Header Metadata

可以在 http 请求头或者响应头里设置多种 metadata 值. 描述了被请求资源的一些信息.

Content-Type 媒体类型

在响应头里设置媒体类型, 以方便客户端解析.

Content-Type: text/html; charset=utf-8

比如常见的有:

  • application/json
  • application/xml
  • image/jpeg
  • text/css
  • application/octet-stream

可以参考 MDN Content-Type

Content-Length

指定 Content-Length 可以告诉客户端该请求的 response body 包含多少字节的内容. 一方面客户端可以检验它接收到的消息体长度是否正确; 另一方面, 可以通过 HEAD 请求获取 response body 大小, 而不需要真正的下载它.

Last-Modified

该标记只用于服务端返回的请求头. 表示该次请求的资源状态变更的时间.

ETag

表示该次请求的资源的版本号. 客户端可以将版本号与该次返回的结果缓存到本地. 配合 If-None-Match 标记, 当服务器下次收到这样的请求时, 如果发现客户端的版本号 与服务端的一致, 就不需要再重新返回一样的数据.

请求头:

Host: blog.biofan.org
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:70.0) Gecko/20100101 Firefox/70.0
Accept: text/css,*/*;q=0.1
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
DNT: 1
Connection: keep-alive
Referer: https://blog.biofan.org/categories/misc/
If-Modified-Since: Thu, 15 Aug 2019 07:43:05 GMT
If-None-Match: "5d550d09-43bb"
Cache-Control: max-age=0

返回的响应头:

HTTP/1.1 304 Not Modified
Server: nginx/1.10.3
Date: Thu, 15 Aug 2019 14:27:29 GMT
Last-Modified: Thu, 15 Aug 2019 07:43:05 GMT
Connection: keep-alive
ETag: "5d550d09-43bb"

参考

  • REST API Design Rulebook
  • fc3986