XX公司APP接口设计规范v1

APP接口设计规范v1

张遂程 2018年02月06日16:15:03

前言

没有最优的方案,只有最适合的方案,本文指出对APP接口设计的一些规范与大家分享和共勉,涉及到APP接口设计规范v1.0,设计案例的分享,和一些PHP编码的要求,目的在于开发出性能优异,结构清晰,维护便捷,安全,和高拓展性的接口。如果有说得不正确的地方,也请大家指出。

经验学习

在项目中,要做到融会贯通,首先就应该做到多学习,学习大厂的经验和总结,如果能避免到别家遇到的坑,那么就最好了,如果避免不到,那么也能做到心中运筹帷幄。程序开发中有句很流行话就是,”不要重复造轮子”,要”时刻明确自己是搬砖民工,不是烧砖的窑”。

新浪微博 open api
获取用户详情接口设计 http://open.weibo.com/wiki/2/friendships/friends
{
    "users": [
        {
            "id": 1404376560,
            "screen_name": "zaku",
            "name": "zaku",
            "province": "11",
            "city": "5",
            "location": "北京 朝阳区",
            "description": "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。",
            "url": "http://blog.sina.com.cn/zaku",
            "profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1",
            "domain": "zaku",
            "gender": "m",
            "followers_count": 1204,
            "friends_count": 447,
            "statuses_count": 2908,
            "favourites_count": 0,
            "created_at": "Fri Aug 28 00:00:00 +0800 2009",
            "following": false,
            "allow_all_act_msg": false,
            "remark": "",
            "geo_enabled": true,
            "verified": false,
            "status": {
                "created_at": "Tue May 24 18:04:53 +0800 2011",
                "id": 11142488790,
                "text": "我的相机到了。",
                "source": "<a href="http://weibo.com" rel="nofollow">新浪微博</a>",
                "favorited": false,
                "truncated": false,
                "in_reply_to_status_id": "",
                "in_reply_to_user_id": "",
                "in_reply_to_screen_name": "",
                "geo": null,
                "mid": "5610221544300749636",
                "annotations": [],
                "reposts_count": 5,
                "comments_count": 8
            },
            "allow_all_comment": true,
            "avatar_large": "http://tp1.sinaimg.cn/1404376560/180/0/1",
            "verified_reason": "",
            "follow_me": false,
            "online_status": 0,
            "bi_followers_count": 215
        },
        ...
    ],
    "next_cursor": 5,
    "previous_cursor": 0,
    "total_number": 668
}
  • 面向对象设计:用户是一个完整的对象,其中每个用户包含一个最新微博的对象,微博对象也是一个相对完整的对象,按照新浪微博的APP接口设计,获取每一个用户列表,都能获取到列表用户的最新微博信息。
  • 错误信息的返回:主接口中没有直接对错误信息的定义,但凡是能够获取到信息,都认为是正确,而错误信息的定义则是用另一种数据格式来表示。
{
    "request" : "/statuses/home_timeline.json",
    "error_code" : "20502",
    "error" : "Need you follow uid."
}
  • 错误信息的说明:’request’表示当前请求的接口;’error_code’表示错误编号;’error’表示错误的提示文字
淘宝开放平台
查询买家信息 http://open.taobao.com/docs/api.htm?spm=a219a.7629065.0.0.5Zpljz&apiId=21348
  • 正常响应
{
    "user_buyer_get_response":{
        "user":{
            "nick":"hz0799",
            "sex":"m",
            "avatar":"http://assets.taobaocdn.com/app/sns/img/default/avatar-120.png",
            "open_uid":"324324324"
        }
    }
}
  • 异常响应
{
    "error_response":{
        "sub_msg":"非法参数",
        "code":50,
        "sub_code":"isv.invalid-parameter",
        "msg":"Remote service error"
    }
}
  • 错误响应也是通过错误code来识别的,每个code对应一个错误内容
其他开放API

除了上文说的响应方式外,还有一种API响应方式也是比较流行,代表者是百度,高德,支付宝等。
- 百度举例

{  
    address: "CN|北京|北京|None|CHINANET|1|None",    #详细地址信息  
    content:    #结构信息  
    {  
        address: "北京市",    #简要地址信息  
        address_detail:    #结构化地址信息  
        {  
            city: "北京市",    #城市  
            city_code: 131,    #百度城市代码  
            district: "",    #区县  
            province: "北京市",    #省份  
            street: "",    #街道  
            street_number: ""    #门牌号  
        },  
        point:    #当前城市中心点  
        {  
            x: "116.39564504",    #当前城市中心点经度
            y: "39.92998578"    #当前城市中心点纬度
        }  
    },  
    status: 0    #结果状态返回码  
}
  • 支付宝举例
{
    "alipay_trade_precreate_response": {
        "code": "10000",
        "msg": "Success",
        "out_trade_no": "6823789339978248",
        "qr_code": "https://qr.alipay.com/bavh4wjlxf12tper3a"
    },
    "sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
}
  • 这类API相对新兴设计,在API响应上,不区分正确响应和错误响应的结构,采用统一返回方式,其中返回的code 来区分正确还是错误,其中的message来分别给出正确和错误的响应消息。
我们自己的API响应规则

选型我们自己使用的API相应规则如下

正常响应示例

{
    "status": 1,//状态值是1
    "error_code": 0,//同时错误代码是0表示无错误
    "message": "获取成功",//提示操作成功信息
    "data": []//主体返回内容
}

错误响应示例


{
    "status": 0,
    "error": 20102,//2:业务级错误(1代码系统级错误)固定一个字符;01:指的是01这个业务比如保洁 固定两个字符;02具体错误信息固定两个字符,会整理成一个对照表格,前端需要翻译成友好的提示
    "message": "用户id不能为空",//给前端程序员的不友好提示,指明错误的原因
    "data": {}//data字段固定
}
小结
  • API设计中,要根据自己的业务类型和面向群体来综合考虑
  • 都对错误级别进行了划分,并用不同的错误code来表示
  • API面向对象设计并不是面向页面设计,这样的API就具有了多端不同展示的能力
  • 响应主体设计中,个人比较倾向统一的返回,也就是现在我们正在使用的三段式返回,不同的客户端不用去写过多的兼容代码和错误处理,错误处理全部由服务端来完成。
  • 错误处理,目前我们的错误处理机制都还比较简单,就APP而言,只有 ‘0’ ‘1’ ‘1001’,三种识别码和对应的中文提示内容。如果我们后续要支持多种语言的提示,就必须使用error_code,然后由客户端自行提示。

接口设计规范

与前端交互部分

这里概念的定义为与APP部分相互的部分,我们将从安全,版本兼容,命名规范,迭代,面向对象等多个方面说起

接口安全部分

在app的后端设计中,一个很重要的因素是考虑通讯的安全性。

避免信息的泄露,最简单的方案是所有涉及到安全性的api请求,都必须要使用https协议。

因此,我们需要考虑的要点有:

  1. 在app和后台,都不能保存任何用户密码的明文
  2. 在app和后台通讯的过程中,怎么保证用户信息的安全性
  3. 在app中,根据安全考虑,用户的操作分为两类:
      1. 用户登录
      1. 注册操作
        用户的其他操作
  4. 在第一点,用户登录注册操作中,是会出现用户密码,所以在这个过程中,必须要使用https通讯,保证通讯的安全。
  5. 在第二点,用户的其他操作,怎么保证这部分通讯的安全呢?
    在我们的设计中,是采用了公钥加私钥保证安全。用户的id是公钥,通过一定的算法对用户的id进行加密得到一个加密字符串是私钥。当用户登录或注册后,通过https把公钥加私钥返回给app客户端。
  6. 但这个方法有个缺点,当别人截获了这个url时可以重复使用,所以有个改进方法是在传递的参数中增加时间戳,当发现这个时间戳离现在的时间已经很久了,就判断这个url已经失效了。但用时间戳怎么保证app的时间和服务器的时间同步?
    可以在app每次启动和注册登录时和服务器同步时间,然后在app内建一个时钟,时间戳在这个app的内部时钟获取,防止用户修改了手机的时间。
  7. 当然,这些操作做完了,也不能保证100%的安全,只能为攻击增加成本。
效率

APP对服务器端要求是比较严格的,在移动端有限的带宽条件下或者弱网络下,要求接口响应速度要快,,抛开后端的开发框架效率来说,对数据要求也比较严格,如果能做到app需要什么数据就传什么数据,不可多传,过多的数据量影响处理速度,最重要的是影响传输效率那么自然效率是最高的,但是这之间也要有个取舍,效率和接口设计思想之间,后面我们会提到面向对象的设计思想。

面向对象的设计思想

Restful风格:RESTfu设计原则,它被RoyFelding提出(在他的”基于网络的软件架构”论文中第五章)。而REST的核心原则是将你的API拆分为逻辑上的资源。这些资源通过http被操作(GET,POST,PUT,DELETE)。但现在看,一般的操作只有两种:GET ,POST。

  • 这个设计原则最简单的应用就是面向对象设计而不是页面来设计api。最开始的时候,app的一个页面需要什么数据,api就返回什么数据。结果随着app的UI不断改版,需要的数据不断变化,不停地修改api,最后当api的改动会影响以前的版本的时候,只能写一个新的api版本,最后弄得api中有很多version/2,version/3这样的标志,恶梦!
    但根据object来设计,又有一个问题,一个大object可能包含很多小object,是一个api返回全部小object,还是分为多个api返回?根据业务和技术,带宽等仔细考虑吧。
  • 目前我们的接口设计是根据业务来定制接口和返回,假设页面上只显示五个字段,那么后端就需要针对这个页面进行设计。
  • 当然这这样的好处是显而易见的,在和客户端交互的过程中,传输的数据全是有用的数据,极大地节约了网络资源,而且只需请求一个接口,接口就返回了所有界面显示的数据,在弱网状态下,加快响应速度。
  • 新浪微博的做法:打开个人中心,会分多次进行请求,’users/counts’批量获取用户的粉丝数、关注数、微博数,’users/domain_show’个性域名相关,’users/show’获取主要信息,这是比较极端的做法,仅供参考。
  • 下面是一个简单的例子
    image
    返回的数据结构如下
{
    "brand_name": "奥迪",
    "car_model": "SUV",
    "emission_standard": "国五",
    "car_owner": {
        "name ": "张三 ",
        "driving_years": "5年",
        "id": "666"
    }
}

其中车主是一个对象,车子是一个对象,两者是既有关系又相对独立。
总结建议是,新设计的接口,需要考虑到多端不同展示,尽可能的偏向于面向对象,少量特殊处理可以面向页面。当然,后端代码上,都是以对象的形式存在,逻辑必须清楚。

API命名规则

其中一个原则,一看api名字就知道这个api是干啥。但是有个问题就是当你要负责几十甚至上百个api,你就知道不能”望名知api”是个什么样的痛苦。

就拿一个接口来举例吧

'/User/userRedDot/version/1'

这是我们在使用的一个接口,从接口名字来看,不难看出User这个是用户相关的一个功能,然后userRedDot小驼峰命名指的是用户小红点,然后接口的版本号是第一版。以上4部分构成了一个完整的接口命名。

传参规则

接口文档中是会注明不同的接口该使用不同的传参方式

header参数部分:请求头部一般放入鉴权的相关参数,比如用户的token和签名,设备id,APP的标识,userAgent自定义等。

除去鉴权的参数,其他就是接口的入参传递(文档会注明传递方式):
1. 一维参数 按照POST/GET按照普通的form-data和urlencode方式即可
2. 多维参数 按照POST方式,并把body放入json的形式传递。
3. 新增数据 POST
4. 获取数据和修改数据用GET

接口使用规则

系统级接口需要独立于业务之外使用,对于系统级接口,需遵循接口使用规则,对于非系统级接口,可由具体业务实现。但是安卓和ios需要统一。

打个比方,获取用户权限的接口,接口的使用规则由产品给出的,切换tab和从后台返回。

再比如,获取编辑用户爱好,婚姻情况,个性签名等筛选数据,按照接口使用规则,应该在进入用户中心点设置的时候请求,现在是在打开APP地方的进行请求,不符合接口使用规则。原因也在于以前没有给出接口使用规则。

特殊处理的接口需要在接口文档上注明使用规则,比如接口的先后顺序,接口的使用环境和频率。

对于接口返回,也需要安卓和ios进行同步处理,操作成功和 操作失败的信息提示,成功是都不处理还是都处理,失败的提示信息怎么处理,操作失败的时候提示信息需要明确。两个客户端不应该存在不同的处理方案。

兼容性原则

接口不可能永远不变,它会随着需求的变化而做出相应的变动,这种变动也可以理解为兼容或者不兼容。大部分情况下直接在这个接口上叠加版本号,并兼容旧版本。App的新版本开发传参时则将传入新版本的version。

接口的变化一般会有几种:
1. 数据的变化,比如增加了旧版本不支持的数据类型(兼容:新增版本号,接口增量更新)
2. 参数的变化,比如新增了参数(兼容:新增版本号,接口增量更新)
3. 接口的废弃,不再使用该接口了(不兼容:原接口指定版本废弃,后端逻辑处理;原接口所有版本废弃,如果是业务流程修改,则停用原接口,并新开接口)
4. 如果整个接口系统的根基都发生变动的话,比如微博API,从OAuth1.0升级到OAuth2.0,整个API都进行了升级,就无法兼容,只能进行版本强制升级了。
有时候,一个接口的变动还会影响到其他接口,但做的时候不一定能发现。

服务端异常处理

服务端的程序在运行的时候,可能因为一个数据的转化或空指针异常什么的,都不能让程序奔溃,需要捕获异常并对异常进行处理,并返回明确的数据状态信息,不管是成功的,还是失败的,都必须要有数据返回给APP客户端,否则,接口的协议失去了所有的意义

  1. app客户端的语言 java和object-c都是强类型语言,所以怎么处理空值显得特别重要,不合理的设计很容易造成app的闪退。

  2. 从后台的角度来说,api中返回的数据中,正确值和空值的类型必须一样,举例,用户名的字段是“realname”: “xxx”,如果用户名为空,则应该返回“realname”:”“。如果返回值是一个array,空数据则返回一个空array,如果返回值是一个对象,空数据则返回一个空对象,绝对禁止null值。

  3. 对于客户端,必须用个全局的函数来处理所有api的返回数据,需要有一个机制:对于某个客户端需要数据,如果api中缺失,客户端自动补上并给予默认值。

  4. 同时,在数据库设计的时候,一个合理的设计必须是所有字段都有默认值,不应该允许null值。null在大量的语言和数据库中,会带来无穷的问题。

  5. 如果服务端是php,还有一个问题,php中数组和字典都是array,但是可以用(object)[]返回对象,但在java和object-c中是不一样,这个问题一定要注意。

数据格式

补充说明下json的六种数据类型数据类型和约定

  1. Number:整数或浮点数
  2. String:字符串
  3. Boolean:true 或 false
  4. Array:数组包含在方括号[]中
  5. Object:对象包含在大括号{}中
  6. Null:空类型

前后端需要对数据类型进行约定:
- 时间日期型数据:直接返回格式化后的时间字符串或者直接返回时间戳
- 数字类型和文本类型:统一使用字符串格式
- 布尔值类型:统一使用字符串’0’和’1’来表示假和真
- 不返回Null类型数据

APP后端代码部分

  • 面向对象设计,必须具有高拓展性来应对各种需求的变更
  • 抽象的颗粒度的把握,颗粒度必须很细,但是又不能太细了,但是实体对象必须是独立的。
  • 代码层次结构必须清晰,明确每一层干什么事情,做到适当的解耦,不依赖用不到的方法和函数
  • 面向接口设计,多人分工合作中,提供的代码的最小单位是接口,使用者无需关注接口的内部实现,提供接口的人后期维护该接口。
  • 代码重合部分,不难发现,目前系统中有很多功能类似的代码,但是又发现这些代码都有用处,维护这些代码就非常痛苦,当要改一个基础的数据的时候,就会去改很多
  • SQL部分,优化SQL查询,提升查询效率,杜绝使用join和写复杂sql等不便于维护的代码,不用jion和复杂sql之后能对系统的扩展和二次开发有帮助,提高系统和数据库的并发[目前能知道的是新浪微博已经全面禁止使用join查询了]。

待商榷问题

  • Herder管理:对herder的规划和规范,包括设计和命名上,还有技术层面上的难题,尤其注意原生里面的内嵌H5页面
  • push到达率:目前的push能否满足现状的需求,如果不满足,那么需要怎么样才满足。是否需要引进新的第三方push
  • 客户端更新和热更新:能否后续的功能用react来编写,集成热更新的能力,原生更新的逻辑梳理,和是否合理,不合理该如何调整。
  • 权限和用户权限:梳理现在的APP权限和用户权限设计模式和交互模式,看是否合理,不合理的话,怎么调整。
  • 接口依赖关系:接口之间原则上的依赖关系不能超过两个,意思是一个接口需求的数据,最多只能从一个接口处获取,如果情况特殊另说。

关于六大设计模式的补充

详情见博客:http://blog.csdn.net/zhengzhb/article/details/7296944

以上内容部分引用他出博客

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值