这篇博文讲先后端交互的Restful API设计考虑。API必定是基于HTTP协议并尽可能靠拢Restful规范设计的。若是不了解HTTP协议,能够参考个人博文HTTP必知必会。关于Restful是怎么回事,能够考虑先参考阮一峰的博文理解RESTful架构;嫌麻烦的能够略过直接阅读个人这篇博文。html
所谓资源,是一种对事物的抽象。一我的、一头牛、一张电影票、一句话、一个想法均可以抽象为资源。json
URL是资源的定位,是一种映射关系,即一个URL必定定位到最多不超过一个的资源。根据URL布局的特色,分为三种类型的资源:后端
集合资源api
对于形如/users
的资源称为集合资源,它表示一群用户。数组
个体资源服务器
对于形如/users/u123
的资源称为个体资源,它表示一个用户,它是经过一个惟一标识的id(即u123)来肯定这个用户。restful
子集合资源架构
对于形如/users/u123/messages
的资源称为子集合资源,它表示某个用户的一群消息,这个用户是经过惟一标识的id(即u123)来肯定的。app
资源的id对于同种类型的资源来讲必定是惟一的。也就是说,肯定一个个体资源只须要经过下面的方式便可布局
/messages/m123
而没必要
/users/u123/messages/m123
资源自己是一种抽象,它必需要转化为一种机器可读的形式才能进行传输和处理。表述方式的例子如表单形式、XML、JSON等。能够经过HTTP头Content-Type来指定资源的表述形式,常见的例子:
这里的设计中只考虑一种表述形式,即JSON。但愿这一点不会给API的调用带来困扰。
对于的基本的增删改查操做,除了定位到资源之外,只须要附加一个HTTP方法够了。根据Restful规范,方法对于集合的意义通常是:
这些方法适用于不一样的URL类型,总结以下:
GET+(子)集合资源
POST+(子)集合资源
GET+个体资源
PUT/PATCH+个体资源
DELETE+个体资源
当对资源的操做跳出了基本的增删改查范畴,就在资源的URL表示以后增长动做的名称便可。这能够经过两个典型的例子来阐述。
这个属于对集合资源进行的操做。其接口表示可设定为:
只需在集合资源的URL表示(即/users)以后附加动做名(即/login)便可。在这种状况下,POST是典型方法。
这是一对接口,其中一个是对一本书进行标星操做,另一个是对其进行取消标星操做。这两个接口都属于对个体资源的操做。其接口表示可分别设定为:
首先,须要在个体资源的URL表示(即/books/b123)以后附加动做名(即/star)。其次,这里用到对立的两个方法POST和DELETE。
一个查询接口会返回一个资源数组,但有时咱们须要知道知足某个查询条件的资源总数。这个在集合资源的URL以后附加动做count便可。例如:
注意,这时分页控制无效。
在参数设计里,一个基本的设计原则是要保证简洁,避免嵌套过深。参数的格式能够根据实际状况限定为几种或不限格式。不过,至少保证表单格式和JSON格式这两种格式的支持。其中JSON格式支持任意的嵌套;表单格式对嵌套的支持不理想。
参数分为通常参数和控制参数。从形式上看,控制参数如下划线开头。这么设计是为了与通常参数进行区分。通常参数例如name、age等,控制参数例如_sort等。
这里的筛选只支持彻底匹配,适用于GET集合资源的接口。筛选的方式是简单直接的,直接是字段名=值
的形式便可。例以下面的接口返回年龄为18的全部男性用户:
GET /users?age=18&gender=male
排序参数_sort是逗号分隔的字段列表,以+/-表示升/降序。
分页参数_range的构建也是直接的,如下划线分隔它的起始和结束资源的序号。资源计数从1开始,这点要尤为注意。
说清楚内嵌的用法,先定义一个资源Book:
{ id: 'b123', title: 'xxx', author: { id: 'u123', name: 'yyy' } }
经过GET接口获取的资源表述中,对于内嵌的资源默认只会返回其id,而不会返回其完整表述。例如调用GET /books/b123
返回的数据是:
{ id: 'b123', title: 'xxx', author: { id: 'u123' } }
这个时候,想要获取完整的author资源,须要再调用GET /users/u123
。
然而,经过_embed参数,能够一步就直接返回包含完整User资源的author连接,就像咱们一开始定义的那样。调用GET /users/u123?\_embed=author
,返回如下的结果:
{ id: 'b123', title: 'xxx', author: { id: 'u123', name: 'yyy' } }
多个内嵌资源用逗号分隔便可。
操做的返回内容,它的表述格式是可选的。只限定为JSON格式是一种可选的简洁方案。
不一样的操做类型,其参数和返回值模式是有必定规律性的。现总结以下:
这个操做请求的是一个资源集合,返回的是一个JSON数组。
其参数能包括:筛选、排序、分页、内嵌。
这个操做请求的是一个个体资源,返回的是一个JSON对象。
其参数只包括:内嵌。
这个操做请求建立一个新资源,返回的是一个JSON对象,表述新建立的资源。
其参数就是该资源的表述。
这个操做请求更新一个旧资源,返回的是一个JSON对象,表述更新后的资源。
其参数就是该资源的表述。
这个操做请求删除一个资源,无返回值,无参数。
其余操做视状况而定,通常无返回值,无参数。
任何操做都会发生出错状况。出错的缘由有不少种,有源于客户端的,也有源于服务器的。有预料中的,也有预料以外的。对于出错状况,服务器要向客户端发送一个状态码及附加一个JSON格式的错误消息(这里像返回值的考虑同样也只考虑JSON格式了)。一个例子就是:
401 Unauthorized { message: "没登陆" }
这里的message字段做为错误状态的描述,做为解释出错的缘由。若是表述的合适,能够做为最终用户的提示信息,直接在弹框中显示。
这里面没有考虑加入更多的字段了,好比一个code字段来更细致的区别错误的类型。这种考虑是基于客户端对于接口调用出错无能为力,通常能作的就两种:
关于用户的受权在HTTP和Restful中的方案,市面上有不少种。这里介绍的是一种Token机制。很简单,用户经过某个接口(例如/users/login
)获取受权的Token,而后每次调用接口时将这个Token附加到Header Access-Token中。
用户的Token不只用于受权,也用于标识用户的身份。当须要传递用户id的时候,每每发现用户的id信息能够从Token中获取。举个例子,id为u123的用户调用以下接口时:
GET /users/u123 Access-Token: 包含u123的受权信息
其中Token信息能够从相应的Header中获取,因此此时明确标明id u123没有必要。此时能够用一个占位符()占位一下便可。
GET /users/_token Access-Token: 包含u123的受权信息