最近公司内部在重构项目代码,包括API方向的重构,期间遇到了很多的问题,不由得让我重新思考了下。
- 一个优雅的API该如何设计?
- 前后端分离之后,API真的解耦分离了吗?
- 不断的版本迭代,API的兼容性该如何做?ps.这里所说的API仅为Web API,提供APP\WEB开发使用。
年前,我司内部的接口已经进入了一个完全的重构阶段,参考了市面上各大平台的API和文档,自己也总结出了很多的心得。这里向大家分享一下,接下来一个月,我们向从下面几个方面向大家介绍一个优雅的API(至少我认为挺优雅)该如何设计。
ps. 打一个广告,公司内部现在在招聘各种技术岗位,Java、Android、前端等,待遇保证能让你涨30%,有兴趣的朋友可以加韬哥的微信(微信号:stchou_zst),二维码在文章最后。
一个移动应用的从无到有,必须经过需求讨论、交互/UI设计、数据库设计、API设计、APP开发、联调、测试等阶段。而在整个研发的流程中API的设计有起到了承上启下的作用。
我们这里从新回顾一个APP迭代的开发流程:
需求 —— 采用用例图描述需求
分析 —— 明确解决问题的细节
设计 —— 给出交互、设计解决方案
开发 —— 将类用某面向对象语言实现
测试 —— 单元测试等
通常,我们都会在需求理清楚之后,产品给出交互图就开始了整个数据库设计、UML、API开发等等。
等等,貌似有哪里不对。设计出来之后,对接的人往往是前端\客户端研发同事,后台同事只管需要下发哪些数据,真的不需要理解前端的交互吗?
作为后端研发人员,你的用户是谁?——毫无以为,肯定是调用API的其他段的开发同事。那么API的开发就得对用户负责(负责,并不仅是写一个方便阅读的文档而已)。
都是你需要考虑的。
这里我们也不卖关子,直接说出鄙人得出的结论:
需要参与计算的值统一按照存储类型下发,仅作为显示的值统一按字符串下发。
### 后台研发:前端展示关我屁事!
我们的结论说起来很简单,但是在实际的工作中我们能够看到,许多的同事并没有一个全局的可发展的思维,我能做出来就行了,需要的数据都有,你们怎么展示,怎么交互我不管了。
ps.越是在大型企业之中,牛人越多,牛人越多的地方自以为是的人就越多。别问我怎么知道的,鬼知道我经历了什么。
多说无益,马上来个Demo,如下所示,我们要做一个产品的详情页:
这个页面看起来功能并没有多少,简单分析一下:
大概估算一下客户端研发时间,3天左右,够了。
Ok,当你你屁颠屁颠的向上级汇报你的工作量完了之后,1天后API开发好了,简单的调了一下API你瞬间就石化了。API返回结果如下:
JSON
{
"totalCount": 99,
"data": [
{
"id": 8055,
"sTitle": "浙金信托-汇城47号",
"productTypeId": 1,
"zdPrice2": 0.93,
"nianHuaShouYiStart": 6.7,
"nianHuaShouYiEnd": "7.0",
"jdt": 0,
"touZiLingYu": "基础设施类",
"level": 99,
"saleStatus": 20,
"category": 30,
"jdTime": "2017-01-04 09:33:27",
"raiseProgress": "【2017年1月4日9时更新】本期第一期,本期规模不限,开放打款中,封账时间根据进款情况安排,有下一期。(三大一小配比,需要录音录像)",
"touZiMenkan": 100,
"collectCount": 4,
"hasCollect": false,
"redPack": "",
"fundType": null,
"visitCount": 47315,
"docPreviewCount": 4,
"producttagids_intarray": "\t13\t4\t71",
"productTags": "4,基础设施类;13,固定收益类;71,三年期;",
"title": "浙金信托-汇城47号(第1期)",
"bid": 1,
"statusId": 40,
"qiXian": 36,
"peibi": "三大一小配比",
"pmName": "王月",
"pmUserName": "王月",
"daXiao": "严格配比",
"lingYu": "基础设施类",
"shouYiType": "固定收益类",
"payStatus": "半年付息",
"downLoad": "Upload/ProductPDF/20161223/浙金-汇城47号_521.zip",
"groupName": null,
"zdPrice": 0.5,
"addr": null,
"companyId": 23,
"adminId": 521,
"groupMaxPrice": 0,
"nianHuaShouYiExt": "",
"companyName": "恒天",
"fxList": [
{
"title": "100万≤X<300万",
"price": "0.93%",
"isFloat": false,
"earningRate": "6.7%",
"packingRate": 6.7
},
{
"title": "300万≤X",
"price": "0.5%",
"isFloat": false,
"earningRate": "7%",
"packingRate": 7
}
],
"sourceRepayment": "1.安顺市西秀区财政收入\n2.融资人西秀城投的经营收入\n3.担保人西秀工投的经营收入",
"fundInvest": "用于受让西秀城投持有的对西秀区政府的标的债权",
"windControl": "1.安顺市西秀区工业投资(集团)有限公司提供连带责任保证担保\n2.受让西秀城投对西秀区政府已纳入国务院地方债务系统的8.05亿应收账款",
"highlights": "市场稀缺中央《预案》承认地方政府存量债务政信、发债融资主体16年11月已发行15亿7年期债券完全覆盖本次融资本息及期限!",
"productOrganizationId": 307,
"productOrganizationPic": "Upload/ProductOrganization/20160118/2016011818020432129312.jpg",
"bqqsr": "2017-01-03 00:00:00",
"province": 520000,
"proviceName": "贵州省",
"cityName": "安顺市",
"dyl": -1,
"addrId": null,
"updateTime": "2017-01-04 17:58:13",
"listingTime": "2016-12-23 16:29:35",
"parentId": 8055,
"phase": 1,
"issuerCompanyId": 0,
"issuerCompanyName": "",
"issuerId": 2492,
"issuerPhone": "13552818811",
"issuerName": "陈敏 ",
"project": 3,
"attr": 3,
"jianBan": "",
"appointmentCount": 5,
"downloadCount": 716,
"sendEmailCount": 21,
"cashback": "",
"tagsArray": [
{
"id": "13",
"name": "固定收益类"
},
{
"id": "4",
"name": "基础设施类"
},
{
"id": "71",
"name": "三年期"
}
],
"bestEarningRate": "7%",
"bestEarningRate_fore": 7,
"bestEarningRate_back": "0",
"bestPrice": "0.93%",
"bestPrice_fore": 0,
"bestPrice_back": "93",
"bestGroupPrice": "待定",
"bestGroupPrice_fore": "待定",
"bestGroupPrice_back": 0,
"bestEmployeePrice": "待定",
"bestEmployeePrice_fore": "待定",
"bestEmployeePrice_back": 0,
"saleStatusName": "在售",
"isNew": false,
"isHot": false,
"isHotSale": true,
"isRecommend": false,
"packingRate": 0,
"returnCash": 0
}
],
"isSuccess": true,
"code": 0,
"runSpanTime": 41
}
不就是展示页面吗?也没啥交互啊!也没有什么逻辑处理啊!为什么这么难?
看完之后,我相信估计没有一个人是在不看文档的情况下能理解每一个字段是什么信息的。一系列的问题随之出现。
当然,我们不能这么做,这个API让调用它的研发者感到恶心,就是没有服务好用户。
API从数据上必须解耦,不能将整个数据库的理解扔给前端。
重新设计!!!!按照解耦法则分析一下这个页面:
首先,将需求中的展示类型,进行划分
- 左右型
展示key | 展示内容 |
---|---|
KEY | VALUE |
产品名字 | 中融信托-唐昇1号 |
投资期限(月) | 12 |
资金用途 | 基金、股票 |
- 上下型
KEY | 展示key |
---|---|
VALUE | 展示内容 |
demo:
认购金额(万元) | 预期收益 | 返佣比例 |
---|---|---|
300-990 | 6.8% | 登录可见 |
1000+ | 7% | 登录可见 |
虽然,层级比较多,但是我们已经定义了展示类型,前端只需要做循环,就能够将整个页面展示出来,完全不需要了解每个字段什么意思。我们这里称之为:API设计之——键值对大法。
键值对大法虽然好,但是并不是适合于很多复杂显示的交互之中,特别是针对移动APP的研发,我们的页面KV展示的结构也比较少。那么,在移动开发之中我们最常见的交互是什么呢?
毫无疑问——列表页
分析了一下现在项目之中的列表页
那么,常见的列表页交互我们分析一下有:
除去 每一个ListItem 的操作不一样 ,我们发现,其实每一个列表页都差不多。那么,这个地方我们是不是也可以抽象? 抽象到直存在一个页面,里面展示的内容项都是后端下发的?
答案是肯定的,首先我们与后端约定一个item项的type,如:
ListType | 说明 |
---|---|
1 | 产品列表项 |
2 | 收藏列表项 |
3 | 推荐列表项 |
4 | 订单列表项 |
然后,我们可以把通用的交互抽象出来,把整个数据适配器(Adapter)根据规则进行Mapping,指向到每一个单独的ListItem之中。如下:
发现了什么?
如今日头条之中,N多tab,N多不同的ListItem(股票、新闻、图文、视频、头条号等)类型,也就是这么设计出来的。我们这里称之为:API设计之——Type大法。
“大法好,退出客户端思维才能保平安!”。其实,还有很多API设计方向的小技巧,但是上面韬哥觉得是做得较好的地方,先只向大家分享这两个。有兴趣的加个微信一起交流交流。
写在后面,最近快过年了,公司业务繁忙,重构任务重大,更新博客也慢了。希望大家多多包涵。
@author zhoushengtao(周圣韬)
@since 2017年1月7日 23:06
@weixin stchou_zst
@blog http://blog.csdn.net/yzzst