RESTful 是目前最流行的 API 设计规范,用于 Web 数据接口的设计nginx
为了不歧义,文档大量使用了「能愿动词」,对应的解释以下:json
必须 (MUST)
:绝对,严格遵循,请照作,无条件遵照;必定不可 (MUST NOT)
:禁令,严令禁止;应该 (SHOULD)
:强烈建议这样作,可是不强求;不应 (SHOULD NOT)
:强烈不建议这样作,可是不强求;能够 (MAY)
和 可选 (OPTIONAL)
:选择性高一点,在这个文档内,此词语使用较少;API 的根入口点应尽量保持足够简单,这里有两个常见的 URL 根例子:api
https://api.example.com/* https://example.com/api/*
若是你的应用很庞大或者你预计它将会变的很庞大,那 应该
将 API 放到子域下(api.example.com)。这种作法能够保持某些规模化上的灵活性。bash
API 返回的数据格式,不该该
是纯文本,而应该
是一个 JSON
对象,由于这样才能返回标准的结构化数据。因此,客户端但愿服务器回应的 HTTP 头的Content-Type属性要设为application/json。服务器
GET /users/2 HTTP/1.1 Accept: application/json Content-Type: application/json
全部的 API 必须保持向后兼容,你 必须
在引入新版本 API 的同时确保旧版本 API 仍然可用。因此 应该
为其提供版本支持。restful
目前比较常见的两种版本号形式:app
在 URL 中嵌入版本编号debug
https://api.example.com/v1/* https://api.example.com/v2/*
将版本号放在 HTTP Header 头中 经过媒体类型来指定版本信息设计
Accept: application/vnd.example.com.v1+json
HTTP 请求动词一般就是五种方法,对应 CRUD 操做。代理
针对每个端点来讲,下面列出全部可行的 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} | 从某个动物园解雇一名员工 |
超出Restful
端点的,应该
模仿上表的方式来定义端点。
若是记录数量不少,服务器不可能都将它们返回给用户。API
应该
提供参数,过滤返回结果。下面是一些常见的参数。
全部 URL
参数 必须
是全小写,必须
使用下划线类型的参数形式。
分页参数必须
固定为page
、per_page
常用的、复杂的查询 应该
标签化,下降维护成本。如
GET /trades?status=closed&sort=sortby=name&order=asc
对建立新资源的 POST 操做进行响应。应该带着指向新资源地址的 Location 头
服务器接受了请求,可是还未处理,响应中应该包含相应的指示信息,告诉客户端该去哪里查询关于本次请求的信息
对不会返回响应体的成功请求进行响应(好比 DELETE 请求)
请求异常,好比请求中的body没法解析
没有进行认证或者认证非法或失效
服务器已经理解请求,可是拒绝执行它
该状态码表示用户请求的资源不存在,如
都 必须
返回该状态码,若该资源已永久不存在,则 应该
返回 410
响应。
所请求的 HTTP 方法不容许当前认证用户访问
该状态码表示由于请求存在冲突没法处理。
如经过手机号码提供注册功能的 API,当用户提交的手机号已存在时,必须 返回此状态码。
表示当前请求的资源已永久不存在。当调用老版本 API 的时候颇有用
该状态码表示服务器拒绝处理当前请求,由于该请求提交的实体数据大小超过了服务器愿意或者可以处理的范围。
此种状况下,服务器能够关闭链接以避免客户端继续发送此请求。
若是这个情况是临时的,服务器 应该
返回一个 Retry-After
的响应头,以告知客户端能够在多少时间之后从新尝试。
该状态码表示请求的 URI
长度超过了服务器可以解释的长度,所以服务器拒绝对该请求提供服务。
一般表示服务器不支持客户端请求首部 Content-Type
指定的数据格式。如在只接受 JSON
格式的 API
中放入 XML
类型的数据并向服务器发送,都 应该
返回该状态码。
该状态码也可用于如:只容许上传图片格式的文件,可是客户端提交媒体文件非法或不是图片类型,这时 应该
返回该状态码:
HTTP/1.1 415 Unsupported Media Type Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 12:09:40 GMT Connection: keep-alive {"error_code":41500,"message":"不容许上传的图片格式"}
用来表示校验错误
{ "message": "422 Unprocessable Entity", "errors": { "name": [ "姓名 必须为字符串。" ] }, "status_code": 422 }
该状态码表示用户请求次数超过容许范围。如 API
设定为 60次/分钟
,当用户在一分钟内请求次数超过 60 次后,都 应该
返回该状态码。而且也 应该
在响应首部中加上下列头部:
X-RateLimit-Limit: 10 请求速率(由应用设定,其单位通常为小时/分钟等,这里是 10次/5分钟) X-RateLimit-Remaining: 0 当前剩余的请求数量 X-RateLimit-Reset: 1529839462 重置时间 Retry-After: 120 下一次访问应该等待的时间(秒)
列子
必须
为全部的 API 设置 Rate Limit 支持。
服务器遇到了一个不曾预料的情况,致使了它没法完成对请求的处理。通常来讲,这个问题都会在服务器端的源代码出现错误时出现。
服务器不支持当前请求所须要的某个功能。当服务器没法识别请求的方法,而且没法支持其对任何资源的请求。
做为网关或者代理工做的服务器尝试执行请求时,从上游服务器接收到无效的响应。
因为临时的服务器维护或者过载,服务器当前没法处理请求。这个情况是临时的,而且将在一段时间之后恢复。若是可以预计延迟时间,那么响应中能够包含一个 Retry-After 头用以标明这个延迟时间。若是没有给出这个 Retry-After 信息,那么客户端应当以处理500响应的方式处理它。
注意:503状态码的存在并不意味着服务器在过载的时候必须使用它。某些服务器只不过是但愿拒绝客户端的链接。
做为网关或者代理工做的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。
注意:某些代理服务器在DNS查询超时时会返回400或者500错误
对于错误数据,默认使用以下结构:
'message' => ':message', // 错误的具体描述 'errors' => ':errors', // 参数的具体错误描述,422 等状态提供 'code' => ':code', // 业务自定义的异常码 'status_code' => ':status_code', // http状态码 'debug' => ':debug', // debug 信息,非生产环境提供
HTTP/1.1 422 Unprocessable Entity Content-Type: application/json { "message": "422 Unprocessable Entity", "errors": { "username": [ "姓名 必须为字符串。" "姓名 必须介于 4 - 18 个字符之间" ], "phone": [ "手机号码 格式不正确。" ] }, "status_code": 422 }
HTTP/1.1 403 Forbidden Content-Type: application/json { "message": "您无权访问该订单", "status_code":"403" }
HTTP/1.1 429 Too Many Requests Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked X-RateLimit-Limit: 10 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1529839462 Retry-After: 290 Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 11:19:32 GMT Connection: keep-alive { "message":"You have exceeded your rate limit.", "status_code":429 }
{ "data": [ { "id": 1, "name": "Eladio Schroeder Sr.", "email": "therese28@example.com", }, { "id": 2, "name": "Liliana Mayert", "email": "evandervort@example.com", } ], "links":{ "first": "http://example.com/pagination?page=1", "last": "http://example.com/pagination?page=1", "prev": null, "next": null }, "meta":{ "current_page": 1, "from": 1, "last_page": 1, "path": "http://example.com/pagination", "per_page": 15, "to": 10, "total": 10 } }