如何设计一个良好的API接口?
沟通创造价值,分享带来快乐。这里是程序员阅读时间,每天和你分享读书心得,欢迎您每天和我一起精进。今天和大家一起讨论的话题是如何设计一个良好的API接口?
作者:梁桂钊
解读:张飞洪
挑战
API是软件系统的核心,而我们在设计API接口的时候会面临着非常多的挑战:
场景上来看,它是多样的,如何设计一个随处适用的API?
我们所参与的业务不断演进的,如何设计一个有兼容性的API?
我们的软件流程是协同开发的,那我们如何实现对API的统一认知?
今天我想和大家探讨一下如何设计一个良好的API接口,我觉得好的API设计需要同时考虑到这几个要素:标准化、兼容性、抽象性、简单性、高性能,可以说这几个要素缺一不可。
标准化
对于Web API标准化而言,一个非常好的案例就是Restful API。目前业界的Open API多数是基于Restful API规范设计的。
1、等级模型
需要注意的是Restful API它具有成熟度的模型。
其中Level 0是普通的请求响应模式。
Level 1引入了资源的概念,各个资源可以单独创建URI,与Level 0相比,它通过资源分而治之的方法来处理复杂问题。
Level 2引入了一套标准的HTTP协议,它通过遵守HTTP协议定义的动词并配合HTTP响应状态码来规范化Web API的标准。
Level 3中,使用超媒体可以使协议拥有自我描述的能力。
通常情况下,成熟度模型中达到Level 2就已经非常好了。
2、URI
在Restful API中,每一个URI代表着一种资源,是每一个资源的唯一定位符。所谓资源,它可以是服务器上的一段文本、一个文件、一张图片、一首歌曲,或者是一种服务。
Restful API呢,规定了通过get/post/put/patch/delete等方式对服务端的资源进行操作。
因此,我们在定义一个Web API的时候,需要明确定义出它的请求方式、版本、资源名称和资源ID。
举个例子,要查看用户编码是101的用户信息,我可以定义get的请求方式,而他的版本是V1,资源名称是users,资源ID是1001。
这里可以思考一下,如果存在多个资源组合的情况呢?
事实上还可引入子资源的概念,需要明确定义出它的请求方式、版本、资源名称与资源ID,以及子资源名称与此资源ID。
举个例子,要查看用户编码是101的用户的权限信息,我可以定义get的请求方式。而他的版本是V1,主资源名称是Users,主资源ID是1001子资源名称是Roles,资源ID是101。
有时候,当一个自然变化难以使用标准的Restful API来命名时,就可以考虑使用一些特殊的actions命名。
比如密码修改接口,我可以定义Put的请求方式,而他的版本是V,主资源名称是users,主资源ID是101资源字段是password。然后定义一个action的操作是modify。
3、错误码和返回机制
与此同时啊,建议不要试图创建自己的错误码和返回错误机制。
很多时候呢,我们觉得提供更多的自定义的错误码有助于传递信息,但其实,如果只是传递信息的话,错误信息字段可以达到同样的效果。
此外,对于客户端来说,很难关注到那么多错误的细节,这样的设计只会让API的处理变得更加复杂,难于理解。
因此,我的建议是遵守Restful API的规范,使用HTTP规范的错误码。例如,我们用200表示请求成功,用400表示错误的请求,而500则表示服务器内部的错误。
当Restful API接口出现非200的HTTP错误码响应时,可以采用全局的异常结构响应信息。
4、返回体结构
这里列出了最为常用的几个字段,讲一下它们各自表示的含义。
其中code字段用来表示某类错误的错误码,例如前面介绍的无效请求、缺少参数、未授权资源、未找到资源、已存在的错误。
而message字段用来表示错误的摘要信息,它的作用是让开发人员能快速识别错误。
server_time字段,用来记录发送错误时的服务器时间,他可以明确的告诉开发人员发生错误时的具体时间,便于在日志系统中根据时间范围来快速定位错误信息。
此外,不常用字段会根据不同的情况做出有不同的响应。
如果是单条数据,则返回一个对象的json字符串;如果是列表数据,则返回一个封装的结构体,其中涵盖count字段和item字段。
count字段表示返回数据的总数据量。需要注意的是,如果接口没有分页的需求,尽量不要返回这个count字段,因为查询总数据量是耗性能的操作。
此外,item字段表示返回数据列表,他是一个json字符串的数组。
5、小结
总结一下,怎么来理解规范呢?可以说他就是大家约定俗成的标准,如果都遵守这套标准,自然沟通成本也就大大降低了。
兼容性
接着我们再来探讨一下API接口的兼容性。由于我们参与的业务是不断演进的,设计一个有兼容性的API就显得尤为重要了。如果接口不能够向下兼容,业务就会受到很大影响。
例如:
我们的产品是涵盖android、ios、pc端的,都运行在用户的机器上,这种情况下,用户必须升级产品到最新的版本才能够更好的使用。
同时,我们还可能遇到服务端不停机升级,由于API不兼容而遇到短暂的服务故障。
为了实现API的兼容性,我们引入了版本的概念,前面的案例URI中通过保留版本号实现了兼容多个版本。
举个例子,针对要查看用户编码是1001的用户信息,可以分别定义V1和V2两个版本的API接口,然后分别让他们对应两套不完全兼容的业务逻辑特性。
抽象性
通常情况下,我们的接口抽象都是基于业务需求的,因此我们一方面要定义出清晰的业务问题域模型,例如数据模型和领域模型等,并建立起某个问题的现实映射,这样有利于不同的角色对API设计认知的统一。
另一方面,API设计如果可以实现抽象,就可以很好的屏蔽具体的业务实现细节,为我们提供更好的可扩展性。
简单性
简单性的主要宗旨是遵守最少的知识原则。
怎么来理解呢?其实就是客户端不需要知道那么多服务的API接口,以及这些API接口的调用细节,比如设计模式的外观模式和中介者模式都是它的应用案例。
如图所示,外观接口将多个服务进行业务封装与整合,并提供了一个简单的API调用给客户端使用,这样设计的好处是什么呢?就在于客户端只需要调用这个外观接口就行了,省去了一些繁杂的步骤。
性能
同时,我们还需要关注性能,就比如说外观接口,虽然保证了简单性,但是增加了服务端的业务复杂度,同时,由于多服务之间的聚合,导致他们的接口性能也不是太好。
此外,我们还需要考虑字段的各种组合会不会导致数据库的性能问题。有时,我们可能暴露了太多字段给外部使用,导致数据库没有相应的索引而发生全表扫描。这种情况在查询的场景下非常常见,因此我们可以只提供存在索引的字段组合给外部调用。
Result<Void> agree(Long taskId,Long caseId,Configger configger)
在上面这个代码案例中,要求调用方必填taskId和caseId来保证数据库索引的使用,以进一步保证服务提供方的服务性能。
总结
今天给大家侧重探讨的是如何设计一个良好的API接口。
好的API设计需要我们同时考虑到标准化、兼容性、抽象性、简单性和高性能。
其中,标准化的关键在于尽可能少的创建自定义规范和机制,而是共同遵守业内标准,例如HTTP规范和Restful API规范。
通常情况下,我们会采取版本号来解决多版本的兼容性的问题。
抽象性需要确保能够定义出清晰的问题域模型,尽可能屏蔽具体的业务实现细节。
简单性是相对的,需要遵守最少知识原则,让调用方尽可能少的知道内部的调用细节,性能注意的细节就多了,这里主要强调了业务组合和参数组合场景。
如何设计一个良好的API接口?的更多相关文章
- 如何设计一个优秀的API
如何设计一个优秀的API - 文章 - 伯乐在线 http://blog.jobbole.com/42317/ 如何设计一个优秀的API - 标点符 https://www.biaodianfu.co ...
- 如何设计一个优秀的API(转载)
最近在整理框架的一些 API,觉得很有必要总结一下 API 兼容性的设计.下图是我自己当下的一些总结,慢慢维护: 网上搜索了一下,一个多月前,“标点符”已经发布了下面这篇文章,觉得写得非常不错,转载于 ...
- 如何设计一个优秀的API(转)
到目前为止,已经负责API接近两年了,这两年中发现现有的API存在的问题越来越多,但很多API一旦发布后就不再能修改了,即时升级和维护是必须的.一旦API发生变化,就可能对相关的调用者带来巨大的代价, ...
- 前端资讯周报 2.27 - 3.5: 如何设计一个优秀的HTML接口,深入理解line-height
从本周起,每周一我都会分享上一周我订阅的技术站点中,和解决问题的过程中阅读到的值得分享的文章,或者视频教程,又或者图书. 个人认为国外的技术文章质量较高,而且发布的技术资讯也走在行业前沿,所以比较关注 ...
- 如何设计一个异步Web服务——接口部分
需求比较简单,提供一个异步Web服务供使用者调用.比如说,某应用程序需要批量地给图片加lomo效果.由于加lomo效果这个操作非常消耗CPU资源,所以我们需要把这个加lomo效果的程序逻辑放到一台单独 ...
- 一个登陆浏览api接口; 其他相关: Form_with参数的不同写法; 简单使用curl。
eeting-up app: 完成一个需求: 完成:https://github.com/chentianwei411/meeting-up-app 第四步实现API接口 Add api base a ...
- 如何设计一个牛逼的API接口
在日常开发中,总会接触到各种接口.前后端数据传输接口,第三方业务平台接口.一个平台的前后端数据传输接口一般都会在内网环境下通信,而且会使用安全框架,所以安全性可以得到很好的保护.这篇文章重点讨论一下提 ...
- 整合微信小程序的Web API接口层的架构设计
在我前面有很多篇随笔介绍了Web API 接口层的架构设计,以及对微信公众号.企业号.小程序等模块的分类划分.例如在<C#开发微信门户及应用(43)--微信各个项目模块的定义和相互关系>介 ...
- 如何设计一个优雅的RESTFUL的接口
show me the code and talk to me,做的出来更要说的明白 我是布尔bl,你的支持是我分享的动力! 一 .引入 设计接口是我们开发人员的日常操作.当我们把接口交给前端人员时, ...
随机推荐
- 重定向(Redirect)和请求转发(Forward)
一.调用方式 我们知道,在servlet中调用转发.重定向的语句如下: request.getRequestDispatcher("new.jsp").forward(reques ...
- [WC2018]州区划分(FWT,FST)
[WC2018]州区划分(FWT,FST) Luogu loj 题解时间 经典FST. 在此之前似乎用到FST的题并不多? 首先预处理一个子集是不是欧拉回路很简单,判断是否连通且度数均为偶数即可. 考 ...
- 什么是 YAML?
YAML 是一种人类可读的数据序列化语言.它通常用于配置文件. 与属性文件相比,如果我们想要在配置文件中添加复杂的属性,YAML 文件就更加 结构化,而且更少混淆.可以看出 YAML 具有分层配置数据 ...
- dos 循环读取当前文件夹下的视频名字
@echo off for /R %%i in (*.mp4) do ( echo -isma %%~nxi ) pause
- Spring 配置文件 ?
Spring 配置文件是个 XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用.
- SpringBoot 自定义配置文件不会自动提示问题
参阅:https://www.jianshu.com/p/ec3f0b0371e6
- redis主从复制与哨兵高可用
redis主从复制 话不多说,直接看案例: 环境准备, 主从规划 主节点:6380 从节点:6381.6382 运行3个redis数据库,达到 1主 2从的配置 #主库 6379.conf port ...
- jmeter的安装使用
以前没自己做过压力测试,一直都是测试在做.现在需要自己做压力测试了,特别学习下jmeter的使用方法.现在做下记录: 1.下载jmeter,这个忽略,百度到处都是 2.打开jmeter,jmeter的 ...
- carsim的一些注意事项
1.carsim导入simulink中运行的目录下最好有simfile.sim文件,可以再carsim_2016.1_date中找到(文件夹内最下端) 2.carsim导入simulink中如果显示下 ...
- vue打包后空白页问题全记录 (background路径,css js404,jsonp等);
总结一下vue打包后问题全记录:大部分开发者webpack基本上都是拿来就用的(并没有系统化的研究). 一 >>> 打包之后的静态文件不能直接访问:(例如dist)打包后搭个服务器才 ...