【转载】做者:曾健生,公众号ID:appbackendjavascript
比目科技 Bmob后端云php
app和后端的交互,通常都是经过后端提供的api实现。api的设计,估计不少刚进入app后端的小伙伴会一无头绪,不知道怎么入门。下面根据本身3年的app后端经验,总结出下几个api设计原则,给小伙伴参考:html
1. 什么是api?前端
这个问题在之前发表的文章“7.app和app后端的通信”中其实已经回答了,这里再重复一次。java
相信你们都用过银行的柜员机(ATM)的查询余额,转账,取款等操做。程序员
当在柜员机取款的时候,咱们输入要取款的金额,隔一会钱就出来了,若是由于有什么问题不能取款(例如超过取款金额的限制),屏幕上也会显示出错误的信息。web
在整个过程当中,咱们只要输入金额,得到结果(取款成功或不成功),就好了,至于柜员机内部是怎么处理,咱们不须要理会。数据库
柜员机这种把内部的处理遮蔽的作法极大方便了咱们的使用。编程
一样的,在后端,也只提供了一系列的功能给app使用,这系列的功能以api的形式提供。json
api的定义:API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工做机制的细节。
当app调用api的时候,只须要明确下面3点:
1.这个api是干啥的(柜员机例子中,是取款功能,仍是查询余额,仍是转帐)
2.知道要输入什么(柜员机例子中,取款要输入金钱)
3.知道结果是什么(柜员机例子中,取款是成功仍是失败)
至于api内部是怎么处理的,app根本无需理会。
从这里可看出,api能在最大程度遮蔽了app后端复杂性,极大提升了app前端的开发效率。
2. api设计的8点
(1)Restful设计原则
Restful风格:RESTfu设计原则,它被Roy Felding提出(在他的”基于网络的软件架构“论文中第五章)。而REST的核心原则是将你的API拆分为逻辑上的资源。这些资源经过http被操做(GET ,POST,PUT,DELETE)。
在实际的开发过程当中发现,程序员因为在web端养成的习惯,api操做中一般就只有两种方式"POST""GET"。你们可看一下微博的api例子"statuses/destroy",这个很明显是delete操做的api倒是用post方式提交。不是彻底遵照Restful风格的风格。
这个设计原则最简单的应用就是根据object而不是页面来设计api。最开始的时候,app的一个页面须要什么数据,api就返回什么数据。结果随着app的UI不断改版,须要的数据不断变化,不停地修改api,最后当api的改动会影响之前的版本的时候,只能写一个新的api版本,最后弄得api中有不少V2,V3这样的标志,恶梦!
后来在网站的重构过程当中,就根据object来设计api,但根据object来设计,又有一个问题,一个大object可能包含不少小object,是一个api返回所有小object,仍是分为多个api返回?根据业务和技术,带宽等仔细考虑吧。
(2) api的命名
一看api名字就知道这个api是干啥。在创业团队中,通常就只有一两我的负责后台,当你要负责几十甚至上百个api,你就知道不能“望名知api”是个什么样的痛苦。
api的命名,我是挺喜欢微博的命名风格,例如删除微博的api "statuses/destroy",第一个是对象,第二个是对象的操做删除
(3)api的安全性
这点会在之后的“怎么保证app通信的安全性”一文中详细论述。
(4) api返回数据
app客户端的语言 java 和object-c都是强类型语言,因此怎么处理空值显得特别重要,不合理的设计很容易形成app的闪退。
从后台的角度来讲,api中返回的数据中,正确值和空值的类型必须同样,举例,用户名的字段是“realname": "xxx”,若是用户名为空,则应该返回“realname": ""。若是返回值是一个array,空数据则返回一个空array,绝对禁止null值。
对于客户端,必须用个全局的函数来处理全部api的返回数据,须要有一个机制:对于某个客户端须要数据,若是api中缺失,客户端自动补上并给予默认值。这个机制在咱们的实践中大大减小了app的闪退。
同时,在数据库设计的时候,一个合理的设计必须是全部字段都有默认值,不该该容许null值。null在大量的语言和数据库中,会带来无穷的问题。对于这个数据库设计原则,我之前不太明白,如今经历了一年的api设计后,终于懂得。
若是客户端是php,还有一个问题,php中数组和字典都是array,但在java 和object-c中是不同,这个问题必定要注意。
(5)图片的处理
在不一样版本的app中,各类不一样尺寸的手机中,同一张图片显示的尺寸多是不同,若是每次都须要用返回原图,而后在客户端处理,则极大浪费网络资源。而若是是后台处理好图片才返回,则又是一个挑战,怎么有效保存和裁剪多种图片尺寸呢
例如,一开始头像只须要返回60*60的尺寸,后来在新的版本须要返回70*70, 又出了一个新版本,须要返回80*80, 每次增长一个新的尺寸,怎么在数据库上记录下来。这个问题在一开始作api的时候没考虑,后来不得不用了一个极端的方法,没增长新的图片尺寸,就在数据库中增长一个新的字段,保存并生成新的图片尺寸,结果最后数据库的头像字段有"avatar","avatar_60_60","avatar_70_70","avatar_80_80",这种极度恶虐的设计。
最后,针对图片,咱们才用了这样的策略:
(1)客户端本地缓存图片,只有没有合适的图片,才去服务器取。
(2)当客户端须要某种尺寸的图片,由客户端告诉服务端图片的尺寸,服务端动态生成并缓存起来。
例如,客户端须要图片(http://www.baidu.com/img/bdlogo.gif)的80*80的尺寸,则在图片的路径加上宽和高的参数(相似于CDN的机制) http://www.baidu.com/img/bdlogo.gif?w=80&h=80, 则服务器就生成80*80的尺寸并返回。
采用了这样的图片处理机制,数据库中只要有一个字段保存原图就好了,其它尺寸就由客户端告诉服务端动态生成。之后不管什么尺寸的图片,数据库中都不须要记录,数据库只有原图就好了。
注意,如今的文件云存储服务(例如七牛,又拍云)等都提供了这个文件的缩放功能,并且能加速文件的上传下载速度,极大提高了app的用户体验,强烈推荐使用。
(6)返回的提示信息
最科学的状况,服务端只返回信息代码,具体的文字提示由客户端决定。
若是文字信息是由服务端返回,则最起码要区分2种信息:提示用户的信息,提示客户端程序员的信息。这二者的区别:
1.提示用户的信息是要在让客户知道的,提示客户端程序员的信息不须要让客户知道的。
2. 提示用户的信息文字很友好,客户不须要专业基础一看就知道是什么,提示客户端程序员的信息则很专业,例如告诉客户端少传了哪一个参数?哪一个参数有问题等等。
(7)在线api测试文档
咱们网站的api在线测试文档,是使用既是一份在线api文档,也是一个在线测试工具,极大方便沟通和测试。每次客户端程序员以为某个api有什么问题,咱们就是这个在线工具上讨论沟通的。客户端程序员最喜欢这个玩意了^-^。
这个api在线测试文档,是使用了Swagger-UI搭建的。Swagger-UI简单而一目了然。它可以纯碎的基于html+javascript实现,只要稍微整合一下便能成为方便的API在线测试工具。项目的设计架构中一直提倡使用TDD(测试驱动)原则来开发,swagger-ui在这方面更是能提供很大帮助。
下面是用Swagger-UI搭建的api文档中的一个api的例子,可看到,整个api的提交方式,做用,参数都很是清晰明了。
当按了“测试”,就以post方式调用这个api,返回的结果以下:
全部的返回结果,一目了然,cool!!!
api返回的数据,是以json格式返回的。用json格式,最省流量,并且几乎每种计算机语言都支持json格式。用xml的话,太耗费流量了,并且冗余数据多,不适合移动端。
在"app后端"的qq群,有个app创始人使用了这个api在线测试文档后赞不决口,称赞虽然前期的搭建须要花一段时间,但极大提升了app先后端工做的效率。之后有小伙伴问相关的问题,他都强烈推荐这个Swagger-UI。
(8)在app启动时,调用一个初始化api获取必要的信息
经过这个初始化api,获取一下必要的信息,例如,最新的app版本。当发现本地app的版本已经低于最新的app版本,可提示用户更新。固然了,这个提示版本更新的功能不少第三方sdk都提供。
3.如何处理api的版本升级
当app作了大改版后,可能会出现一个问题,发现如今的api已经不适了,就考虑到api的升级,同时为了兼容已经发布的app,原来的api必需要保留。为了不同一个app中调用不一样版本的api,通常就会所有升级api的版本,例如:原来的是“test.com/v1/statuses/destroy”,升级为“test.com/v2/statuses/destroy”。
在api的版本升级时,须要注意如下2点:
1. v2版本的api的controller必需要继承v1版的controller,v2版本的api只重写须要改动的api。
2. 在线api测试文档中详细标明返回内容,已做对比,方便客户端人员的调试。