API是模块或者子系统之间交互的接口定义。好的系统架构离不开好的API设计,而一个设计不够完善的API则注定会导致系统的后续发展和维护非常困难。
以下谈一点API设计的原则。
业务层
业务语义简单明确
一个接口或者说一个api,必定是为外部使用者服务的,因此必须具有明确的业务/使用意图。api的从命名到定义,都必须围绕着这个意图来进行设计,简单明确的命名/参数设计是一个好的api设计的第一步。
定义抽象,稳定,允许多个实现
API的设计需要注意的是,我们给出的api,实际上给出的是一个契约,由于业务实现/系统迭代的关系,内部的实现时常在变化的,但是契约的本质是没有变化的,因此我们定义api的时候,必须要进行一定程度的抽象,能够保证稳定的业务语义。最常见的方式就是,我这个api定义之后,如何方便的进行替换实现,并且外部的服务使用者是不感知我的变化的。
API定义的粒度
这里一个API的设计,至少需要保证原子服务的能力,但是很多情况下,服务调用方并不关心相关的原子服务能力,他所关心的是一个业务的处理。那么这个时候的情况下,我们的需要提供多个维度的api,使用门面模式进行原子能力的封装。
技术层
幂等
一个api的设计必须要进行幂等性设计,幂等性指的是多次的操作不影响第一次操作的结果;那我们常说的curd来说,Query接口具有天生的幂等性;Create多次调用的话容易存在重复创建,因此常用的做法是api设计有uk字段,显示或这个隐式的都可以,客户端必须要保证多次调用这个uk生成是唯一的;update进行幂等,常用的存在状态的话,会用乐观锁来进行校验,或者使用版本号的方式来进行判断;Delete的方式,其实delete多次调用不存在影响第一次调用的情况,只是会带来删除不存在的数据的一个错误提示的问题,这个可以和调用方进行约定,一定意义上,delete操作也是具有幂等性,无需做特殊的处理;
兼容
这个不用说了,api版本的升级,必须要考虑向下兼容;
批量处理
服务端是否提供批量处理的能力,这个一直是有争议的。我们先来看下服务端批量更新的优势和坏处,再根据具体的场景来选择是否进行服务端批量更新;
优势
1、性能的提升
一定程度上面可以进行性能的优化,比如我可以对批次数据进行划分,多线程进行处理,减少远程交互带来的网络开销等;
2、系统负载的转移
客户端的负载转移到服务端,服务端天生是需要进行这么多数据的处理,只是原先是在客户端进行流量的控制,甚至是批量的调用,现在转移到服务端进行批次处理了
3、客户端业务语义简化
批量处理,客户端不用关心一个业务聚合语义上面的数据的完整性和一致性,这部分交由服务端进行统一处理。客户端只需要关注数据结果,制定相关的重试策略即可。
劣势
1、带来了语义上的复杂性
全部成功,部分成功,全部失败,多种状态的处理,需要交由客户端进行处理,并且客户端很多情况下需要关注哪些成功,哪些失败,对于失败的数据需要明细的数据,这样就带来了接口语义的复杂性,丧失了api的简单的原则。
2、幂等处理的复杂性
如同上述,幂等处理需要考虑多数据之间的关联影响,部分成功处理的幂等性如何处理。
3、事务处理的复杂性
对于很多的客户端来说,一批次的数据不具有聚合关系,是允许存在数据状态不一致的(当然这种情况,可以将批量接口作为原子接口使用),并且由于实现的可替换性,是否支持批量的事务性这个需要进行考量
4、性能挑战
服务端实现批量处理,对于批次数据会对服务端带来性能上的挑战,并且不能对客户端进行约束,客户端滥用可能会导致性能问题的进一步恶化。
接口异常规范
需要具有比较粗力度的表示接口成功失败的字段,也有比较具体的明细信息,使用统一的异常码(常见并且精简的);
其他
API接口参数不要过多,不要具有相同参数类型参数,最好进行对象传递,进行防呆处理。