什么是restful API
REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。 他在论文中提到:"我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。REST指的是一组架构约束条件和原则。" 如果一个架构符合REST的约束条件和原则,我们就称它为RESTful架构。
REST本身并没有创造新的技术、组件或服务,而隐藏在RESTful背后的理念就是使用Web的现有特征和能力, 更好地使用现有Web标准中的一些准则和约束。虽然REST本身受Web技术的影响很深, 但是理论上REST架构风格并不是绑定在HTTP上,只不过目前HTTP是唯一与REST相关的实例。 所以我们这里描述的REST也是通过HTTP实现的REST。
RESTful是遵循了REST原则的web服务。在设计RESTful API时,需要关注的点有:
- URL设计
- 状态码使用
- 返回结果
URL设计
RESTful 的核心思想是,客户端发出的数据操作指令都是"动词 + 宾语"的结构。比如,
GET /articles 在这个请求中,GET是动词,/articles是宾语。
HTTP动词
动词通常就是6种 HTTP 方法,对应 CRUD 操作。
- GET:读取(Read)
- POST:新建(Create)
- PUT:更新(Update)
- PATCH:更新(Update),通常是部分更新
- DELETE:删除(Delete)
- OPTIONS: 获取Server端支持的方法
在HTTP规范中,动词都是大写。
动词覆盖
有一些比较老的代理只支持HTTP1.0,所以像PATCH、PUT、DELETE这些动词的请求会被丢弃掉或者改为POST。此时可以通过在request的headre中添加:
X-HTTP-Method-Override: METHOD
这个header来告诉服务端真正使用的动词是哪个,例如:
POST /api/Person/4 HTTP/1.1
X-HTTP-Method-Override: PATCH
此时,X-HTTP-Method-Override指定本次的请求是PATCH而不是POST。这个动词的修改,需要放到代码层来实现。
宾语尽量是名词
宾语就是 API 的 URL,是 HTTP 动词作用的对象。它应该是名词,不能是动词。比如,/articles这个 URL 就是正确的,而下面这些:
- /getAllCars
- /createNewCar
- /deleteAllRedCars
都不是名词,所以不是那么合适了就。 但是也有一些场合不是那么容易找到一个名词的宾语,例如在给一个query做预测的时候,接口一般会写成:
/predict
这样也是合理的。
复数还是单数
关于URL中的资源应该是复数还是单数,这个并没有明确的规定,个人建议用复数。例如:
- /agents
- /users
多级URL?
目前有2种API接口设计习惯,一种是使用多级URL来表示资源之间的关系,比如:
/agents/agent_id/bots
另外一种是避免使用多级URL,例如:
/bots?agent_id=<agent_id>
这2种方案各有利弊,建议使用第二种。 在第一种方案中,如果遇到多个级别的关系,那URL会写的很长,例如:
/agents/agent_id/bots/bot_id/intents/intent_id
读这个URL都会浪费不少时间。而在第二种方案中,我们可以将上级关系通过querystring来传,大部分情况下,只要将querystring当作查询条件就可以得到需要的结果了。
状态码
在restful中,HTTP状态码一定要精确。
客户端的每一次请求,服务器都必须给出回应。回应包括 HTTP 状态码和数据两部分。 HTTP 状态码就是一个三位数,分成五个类别。
- 1xx:相关信息
- 2xx:操作成功
- 3xx:重定向
- 4xx:客户端错误
- 5xx:服务器错误
这5类基本上可以满足日常开发使用,并且每一个错误码都有一个标准(或者约定)的解释。客户端只要查看状态码,就可以知道本次请求的具体信息。
在日常的API设计中,1xx的状态码一般用不到。可以直接忽略。
2xx状态码
200是最常用的2xx状态码,但是更建议用不同的状态码来响应不同的请求,例如:
- GET: 200 OK
- POST: 201 Created
- PUT: 200 OK
- PATCH: 200 OK
- DELETE: 204 No Content
其中,POST返回201,表示生成了新的资源(但是资源并没有随response返回给客户端)。DELETE返回204,表示资源已经被删除不存在了。 此外,还有一个202状态码,表示服务器已经收到请求,但还未进行处理,会在未来再处理,通常用于异步操作。例如:
HTTP/1.1 202 Accepted
{
"task": {
"jobId": "job_id",
}
}
3xx状态码
API 用不到301状态码(永久重定向)和302状态码(暂时重定向,307也是这个含义),因为它们可以由应用级别返回,浏览器会直接跳转,API 级别可以不考虑这两种情况。 API 用到的3xx状态码,主要是303 See Other,表示参考另一个 URL。它与302和307的含义一样,也是"暂时重定向",区别在于302和307用于GET请求,而303用于POST、PUT和DELETE请求。收到303以后,浏览器不会自动跳转,而会让用户自己决定下一步怎么办。下面是一个例子。
HTTP/1.1 303 See Other
Location: /api/orders/12345
4xx状态码
4xx状态码表示客户端错误,常见的有:
- 400 Bad Request: 表示服务端不能理解客户端的请求,未做任何处理。
- 401 Unauthorized: 用户未提供授权验证凭证,或者没有通过身份验证,比如第三方登录时,没有access_token,则应该返回401。
- 403 Forbidden:403表示用户通过了身份验证,但是没有访问指定资源的权限。
- 404 Not Found: 表示所请求的资源不存在,或者不可用。
- 405 Method Not Allowed:表示请求的动词服务端不接受,比如服务端只接受GET请求,但是客户端发了一个POST请求。
- 410 Gone: 所请求的资源已经从这个地址转移,不可用。
- 415 Unsupported Media Type:客户端要求的返回格式不支持,比如服务端只支持JSON返回,但是客户端要求返回XML格式。
- 429 Too Many Requests: 客户端请求次数超过限额(常见于登录次数受限的场景)
5xx状态码
5xx状态码表示服务端发生异常,一般来说API不会向客户端返回过多信息,因此常见的有2个状态码:
500 Internal Server Error: 客户端发送了请求,但是服务端处理时发生意外。 503 Service Unavaiable: 服务器无法处理请求
服务端响应
服务端响应只返回JSON格式的结果。并且header中要有: Content-Type: application/json这个header。 同时,客户端发请求时,也需要在header中添加Accept: application/json。表示客户端接收的是json格式的返回。
当发生错误时,不要返回200状态码。 经常会看到有些API在发生错误时,返回的也是200的状态码,错误信息在response的数据体里,例如:
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "failure",
"data": {
"error": "Expected at least two items in list."
}}
这是一个非常不友好的设计,正确的做法应该是,状态码反映发生的错误,具体的错误信息在response的数据题里,例如:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid payoad.",
"detail": {
"surname": "This field is required."
}}