简评:用一个例子深入浅出讲解了 API 是什么,就算没学过计算机也能看懂。对小白很友好的一篇文章。
(本文翻译,仅代表原作者观点)
本文这个比喻主要适用于 Web API(尽管一些概念也适用于其他类型的 API)。
API 能做太多事了
API 功能非常强大, 能做非常多的事情,但很多小白(非专业人士,但听过这个词)对它很陌生,甚至对技术产生畏难情绪。不用怕,我们今天简单说说 API 是怎么回事。
我们有家银行
想想一下你正在经营一家银行。
银行里有一个很大的很坚固的保险库,还有一个记录人们有多少钱的账本。运作这个银行非常简单(懒惰),给每个来访者开放一次访问权限,没人去检查来访者的身份,银行相信人们会做出正确的操作。
在这个开放的银行,客户想要存钱,需要做的步骤是:
- 拿钱去银行
- 打开保险库,把钱放里面
- 在账本上写着我是XXX,我存了XXX的钱。
- 离开银行。
这种方法有两个问题:
- 保险库的门很难开,需要一定的体力。对弱势群体不是很友好,这可能违反了一些健康和安全的规定。同样,有人手部受伤,或者眼睛看不清,就无法在账本上读写。
- 在这个模式中,银行相信人们是绝对诚实的。显然,正如经验所示,人类不可信赖[1]。我打赌有人会存 100 块,然后在账本上写存了 10000 块。没两天你就破产了。
所以,我们需要进一步的设计银行的流程。
我们请了个银行出纳
既然有上述问题,我们可以雇佣一个聪敏强壮的人来处理所有的保险库访问,我们雇佣了出纳员莎莉来进行这项工作。
现在,我们可以创建一个更好的银行:有一堵墙将保险库和账本与客户分开,客人不可以直接在账本或者保险库操作,如果他们想要存款取款,就要通过我们的友好的柜员莎莉。
客人在银行存钱,现在需要的操作:
- 拿钱去银行。
- 告诉柜员,我是XXX,希望存XXX到我的账户。
- 莎莉拿着钱,放进了保险库,她很强壮健康,她轻松做到这点。
- 莎莉在账本上记录下交易。
- 莎莉回到柜台,告诉客人钱存进去了,你可以走了。
- 客人离开银行。
现在,客人不需要在打开那个庞大笨重的门了,整个流程对于客人来说没有任何障碍。
现在,我们可以介绍 API 的概念了。API 是称为应用编程接口,就是软件系统不同组成部分衔接的约定(wiki 百科说的)。
简单来讲,API 允许你轻松地与其他软件交流,这很重要。
在我们的比喻中,银行有一个很难打开的保险库大门。如果我们让银行柜员开门,那么客户就不用费劲去开门,客户节省时间,他们更开心。用户的满意,银行获得更多业务。
同样,我们抽象出操作的实现细节(例如分配系统内存,远程启动车库门,或向空间发射火箭),这将有助于降低程序员的认知负荷(一个人必须一次记住的东西的数量),从而提高生产力。例如,如果我们制作一个将火箭发射到太空的 API,程序员就可以使用这个 API,眨眼之间,引擎就会点燃,火箭就会直射天空。由于实现细节被抽象出来(隐藏在 API 的后面),我们的程序员不需要知道火箭科学就能将火箭送入太空。
有了这个信息摘要,还有另外一个好处:只要它们遵循相同的协议,组件就可以被换出(swap out)和替换(replace)。银行不需要知道客户是如何到达银行的,客户也不需要知道银行已经把所有的钱都转移到了避税天堂。只要银行柜员还在那里,知道如何取钱,整个交易所将继续进行。
API 无处不在:从操作系统里的简单fork()到复杂的 API(如 Google Maps API),他们都在这里让程序员更轻松。
银行里有什么?
再来看看我们的银行。
你可能注意到了,银行有两部分:前部区域,客户有序的排队;后部区域,处理货币。在中间的柜台,那前后区域被隔离。互动只能发生在中间柜台上的窗口(莉莎)。
在 API 术语中,我们城中间区域为 Interface;这是软件组件交互的地方。在我们的银行,前台后台都知道这个地方的存在,也都同意在这里交换信息。
现在,假设鲍勃来取钱。鲍勃在柜台说「嗨,我是鲍勃,我可以从我账户上取走 500 美元么?」
银行柜员说「当然可以,请稍等。」
莉莎很清楚如何取钱,然后拿到钱给了鲍勃「这是你的钱,谢谢,再见。」
有一次,鲍勃喝 high 了,又来了银行,他问柜员莉莎「库里这个赛季的 2 分命中率为什么提高到了 59%?」
作为银行柜员且压根不看篮球的莉莎一脸懵逼。
在 API 术语中,协议是定义组件如何相互交互的一组规则。双方都必须理解和坚持同样的沟通协议才能成功。在这种情况下,银行柜员理解提款和存款,但她并不理解篮球。
莉莎和鲍勃交流都用普通话,我们称其为格式:它指定如何编码要发送给对方的数据。换句话说,这里的通讯格式是普通话。与协议一样,双方都要理解和坚持这一个是,如果鲍勃觉得自己的广东话很炫酷,对莉莎说「我想撳五百蚊出嚟呀唔該」(我想拿出五百块谢谢)。由于莉莎听不懂所以无法做出任何的操作,信息交换就失败了。
在现实世界中,Web API 的常见格式包括 XML 和 JSON,尽管 JSON 在很流行,因为它比XML 轻而易读,而 XML 在 Java 世界中仍然占据重要的位置,特别是企业级(例如,在 SOAP 中进行会话的 API)。对于需要交换大量数据(特别是多人游戏)的应用,像ProtoBuf和MsgPack这样的二进制协议经常被用来节省空间并提高编码/解码的效率。
最后,我们假设我们也想把业务拓展到股票市场。我们需要一个特殊的银行出纳员来处理股市交易。我们称这个新的股票交易员汤姆:
在 API 术语中,API 端点通常是指在同一个接口中提供特定功能子集的服务提供者。在这种情况下,Tom 和 Sally 都是端点。不同的端点可以有不同的协议和不同的格式。
总结一下:Interface 是不同软件组件交互的地方。一个协议是一组定义它们之间如何相互作用的规则,以及格式定义它们是如何相互交谈。端点在相同的接口内提供不同的功能。
银行柜员还能做什么?
现在我们介绍完 API 的一些基本概念了,再来聊聊 API 的一些常见功能。
这次鲍勃又来取钱了,他试图取出 10000 美金。
柜员在取钱给他之前,一定会查查他账户有没有 10000 美元。API 可以包含验证逻辑,以确保所有的操作都是合法的。
事实证明,鲍勃账户上只有 100美元。我们可以让银行柜员告诉他资金不足。API 可以具有错误报告机制,来指示已经发生的错误。
鲍勃认为这肯定搞错了,并要求银行柜员给出自己名下所有账户单据,以及他在每个账户中有多少钱。原来鲍勃有 200 个账户。一次给完他并不是很实际,所以柜员莎莉一次向展示了 10 个账户。当鲍勃看完 10 个,他就可以继续看下 10个。这就是所谓的分页和分页数据集,可以节省带宽和服务器资源,因为不需要一次获取数据集中的所有内容。如果鲍勃只想知道账户余额,而不是账户有多少奖励积分,他可以要求莎莉只显示余额。这被称为过滤,有助于节省带宽和资源,并且更易于导航。
在检查所有所有账户之后,鲍勃发现自己确实没有 10000 美元。但是他知道爱丽丝买了股票赚了大钱(图6),所以他离开了银行,过一会伪装成爱丽丝又回到了银行,他告诉柜员莎莉「我是爱丽丝,我要取 10000 美元」。
我们让莎莉在取钱之前要验证客户的身份和银行卡,这种情况下,鲍勃没有这些证明,只能灰溜溜的离开银行。授权和访问控制可以内置到一个 API 中,以确保只有经过授权的人员才能访问特定的数据。
最后,在试图取出 10000 美元失败后,鲍勃气急败坏的返回银行,每次只取出 0.01 美元(可能是为了报复莎莉)。如果莎莉做了,会耗时耗力。我们可以指定取钱的频率,比如 10 分钟只能取一次钱,如果鲍勃真想每次去 0.01 美元,那他要在银行待上一段时间了。我们可以通过限速来控制服务器的资源分配,保证用户不会滥用服务。
API 与上述功能相结合,可以充当防火墙,保护资源不被误用,同时允许合法的请求。
能力越大责任越大
API 真是好东西,但是如果设计的不好,会让开发者很难受,以下是我认为在设计 API 时一些有用的标准:
- 明确每个端点的作用。你的端点应该有基本的名字,且要清晰,言简意赅。
- 错误应该是清晰的,说人话。告诉客户他们在银行里没有足够的余额是对的。告诉客户发生了「错误#506340」,那就让人摸不清头脑了。尽管通过返回一个错误代码来保存几百个字节的数据可能是很有吸引力的,但事实上,这只会阻碍客户选择你的银行。
- 记录一切。这是非常重要的,如果你希望你的开发者每次遇到错误时都不要把头发拉出来。给他们充分的支持,清晰,简洁的记录。
- 保持一致。如果 API 的某些端点和其他的不同,那么你用户在 Deadline 之前会疯狂 Google 搜索(顺便喷你)。确保你的命名规则,错误处理和其他行为在所有端点上保持一致。
- 多听取反馈。想想开发人员将如何使用你的 API,并确保它尽可能简单直观。
本文总结了我对 API 的看法。很显然,这篇文章地将 API 这个很复杂的世界简单化了,很多地方不严谨,但希望这能讲解一下 API 的基本知识,让你产生一些基本的了解,如果能够对你有所帮助,那简直太棒了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。