RESTAPI设计,决定了你的薪资水

前言

作为一名优秀的后端程序员,你照着产品需求设计好了模型,设计好了关联关系。

把这些模型和关系一再打磨了一番之后,你想是时候把API设计出来,与前端沟通了。

这时候问题来了:

一旦API进入前端APP代码,或者是被你的顾客广泛使用的话,再来大改就非常麻烦了。比如说,如果APP版本1.0用了一个接口A,这个接口A如果要进行大改,那么必须将A维持至所有用户升级过APP1.0后。

那么怎么样避免API发布之后大改呢?有没有一些提前可以注意到的设计准则可以帮我们避开API设计中的各种坑?

答案是有的。网上充满了各种对API设计的建议,而这篇文章里我们结合卡拉搜索设计API的经验,把RESTAPI的最佳实践和常见的坑都总结出来,做成一个教程,希望可以在帮到正在设计/使用API的你。

RESTAPI是什么-程序员与服务之间沟通的语言

任何语言的本质都是一套规则的合集。比如说,中文里要求句子要有主谓宾,而作为母语为中文的我们,一旦有人说了一句缺少主语的话,我们会直觉性地感觉很奇怪。

比如说,如果有人对你说“是一个神人”。

你会直觉地问:究竟谁是一个神人?

同样的,在各个程序的沟通中,或者各个服务的沟通中,我们也需要类似“语言”的东西,让我们可以不需要太多的上下文,就可以前端理解后端、后端也理解前端。

设想一下,有多少次你跟前端一起需要前后端联调?有多少次前端觉得你定义的API不够方便直观,一定要你多返回一个参数或者改一下端点路径?

其实本质上,你们在联调时就是在尝试设计一个"语言",以方便互相可以更容易地理解对方。

比如说,后端会要求前端说,你调用POST/user/abc就可以创建一个名为abc用户了。

短线来讲这当然没问题,你们可以几乎任意地定义API端点,任意地调整传递的参数。但是一旦项目开始变复杂,问题就开始出现了。

首先大家有不同的经验和喜好,对API的定义可能千差万别,所谓众口难调

系统开始复杂后,各个系统之间的API因为定义的人的不同,会开始出现不一致,导致每个端口调用前需要详细阅读文档(如果有的话)或者与API设计者无穷无尽地讨论和会议

如果你的API是面向客户的,比如如果你是一家软件服务公司,那么你自定义的API会增加客户接入的成本

等等等等

因此,要是有一套人类通用的"语言“或者”规范“,来指导大家定义API的方式,那样该多好?

RESTAPI就是这样一种规范,它是目前整个互联网应用最广泛的API规范。有意思的是,REST是由它的提出者RoyFielding在他读书期间,写的博士论文里提出的。

总结一下,RESTAPI有一套API设计的准则,它规范了API设计的框架,使得服务间、程序员之间有一个通用的沟通语言。

RESTAPI内具体规定了什么

RESTAPI规范了API设计的两大核心原则

API应该作用于Resource(资源)上

对资源的操作应使用对应语义的几种操作,包括:GET,POST,PUT,PATCH,DELETE

我们来详细解释一下这两点

什么是RESTAPI里的Resource(即资源)

这里的资源是指你的API用户可操作的逻辑对象,举个例子

如果你的API中允许调用者对用户进行操作,比如说用户注册,那么API类似于POST/users在这里,资源即为users。在很多情况下,API中的资源与你的数据模型(也就是数据库的表)是一一对应的。当然也有例外情况,比如说你的数据库中存有用户,但是你现在想要让调用者可以创建"管理员",那么API可能是POST/admins然而,你的表中并没有admins这个表,而是否是admin是Users表中的一个属性,比如role=admin。

请注意,RESTAPI中的资源一定需要是名词,即一定是一个实在存在的概念比如用户,帐号,车票等,或一个抽象的概念比如权限等。如果你需要提供一个创建某种资源的API接口,上述则可以表述为POST/indexes,POST/accounts,POST/docs等等。

通常对于资源的命名,我们建议统一命名为为英文的复数。比如说users而不是user。同时请注意保持一致性,在所有地方用一样的复数。

什么是RESTAPI里的操作

一旦你定义了资源,接下来你需要定义允许调用者在这些资源上做什么操作。

比如说,以携程抢车票网站为例,我们可能允许调用者进行以下操作

GET/tickets-列出所有车票

GET/tickets/-列出id为这张车票的信息

POST/tickets-创建一张车票

PUT/tickets/-更新这张车票的信息

PATCH/tickets/-部分修改这张车票的信息,比如只修改车票价格

DELETE/tickets/-删掉这张车票

请注意,到这里为止,你应该可以总结出来REST的大致设计思路了。它由两部分组成,第一部分是操作,第二部分是可操作的资源。比如上文中的GET/tickets,操作是GET,可操作的资源是车票。

那么读到这里,如果你严格遵循了REST的设计准则,以及你的调用者也了解REST的准则的话,那么对于很多API调用,你们不用再参考互相写的文档了。如果需要调用一张车票的信息,你的调用者自然会知道应该用GET去查看一个车票资源的信息,即GET/tickets/:ticketId。这样就极大降低了沟通成本和出错成本,提升效率。

如何在API中表示实体(数据库表)间关系

在后端设计中,有的资源逻辑上无法独立存在。比如说,在卡拉搜索的例子里,用户的文档是无法独立于索引存在的。那么自然地,我们用GET/indexes/index_abc/docs/1来表达获取索引index_abc中编号为1的文档。因此,对于所有资源需要依赖于另一个资源存在时,我们就按顺序在端点中将资源列出来。对于卡拉搜索中,索引和文档的关系,我们有以下接口

GET/indexes/index_abc/docs/1-获取indexid为index_abc下的id为1的文档

GET/indexes/index_abc/docs-获取indexid为index_abc下的所有文档

POST/indexes/index_abc/docs-在indexid为index_abc的索引中,添加文档...

如果一个资源可以独立于另一个资源存在,并且你期望你的API调用者频繁调用,那么可以考虑直接提供子端点。比如说,如果一个宠物店主人和宠物信息分别都常常被同时调用,那么你可以考虑

GET/owners/-获取所有主人信息GET/owners/1/pets/获取id为1的主人的所有宠物GET/pets/-获取所有宠物信息(宠物店所有宠物)GET/pets/13-直接获取id为13的宠物

RESTAPI中如何表示一个动作

有时候,当我们试图表达一些接口时,会发现REST的准则很难直接应用。比如说,当你需要一个接口让用户登录时POST/users/signin但要注意,这里的signin即登录,是一个动词。这里是采用REST准则时需要考虑的地方,你有三个选择

如果你希望严格地遵循REST原则,那么你需要找一个替代动词的名词。比如说,这里的signin可以替换为login。或者,如果你是以token密钥的方式登录的话,也许可以改为POST/users/token,即创建一个usertoken(也就是登录了)

在某些实在困难的地方,放弃严格的REST原则

参考一些成功的RESTAPI并寻找类似的API,参考他们的命名设计

对于3,我强烈建议你参考github的API,原因不光是其极为规范,还有它覆盖了极多的API调用的情景,因此大概率你可以找到个类似的命名参考。

比如说,在github上,如果让你来设计加星这个操作,你会把端点被设计成什么样?

Github把加星端点设计为PUT/gists/:id/star,把取消加星设计为DELETE/gitsts/:id/star。这样就完美地遵循了REST名词作为资源的准则,把动词"加星“完美地用PUT/DELETE两个操作,清晰地表达了出来。

RESTAPI设计常见问题和建议

上面我们描述了REST设计的准则,而在准则中并不包括其它”最佳实践“。

这里的最佳实践,其实并没有什么客观标准,只是软件工程和架构经过多年的发展,RESTAPI的设计也从十几年前简单的web应用,到应用到现在越来越复杂企业级软件中。因此,如果你刚刚开始学习RESTAPI的设计,参考这些实践经验将会有非常大的帮助,可以帮你少走不少绕路。

RESTAPI如何区分版本

在设计RESTAPI时,你应该时刻准备好不断更新API。想要把API稳定后再一次发布多数情况下是不实际的——老板要催进度,用户要催功能。因此,在设计API的时候就应该把支持API改动设计到API本身中。

多数情况下,在一版API已经成熟的前提下,可以提前发布,同时开始进行下一版的开发。而你只需要在URL中区分好API的版本即可。

比如说,如果在大致将v1开发完毕后,v1前缀的API就应该稳定下来,所有的改动进入v2。同时你应该开始通知所有使用v1的用户,给他们几周到几个月的时间,帮助他们平滑迁移到v2

带有版本前缀的API示例如下

GET/v1/indexes/GET/v1/indexes/abc/POST/v1/indexes/

RESTAPI应该返回什么

作为一个通则,我们建议RESTAPI永远返回JSON格式的结果。

原因有几个:

首先,JSON作为互联网上使用最广泛的格式,在几乎任何语言的任何框架中都有广泛的支持。

同时,由于其高度的可读性,如果需要阅读返回内容,JSON会让你的调用者阅读起来方便很多。

最后,JSON的高压缩率可以在需要时方便地帮你提升传输效率和速度。

为什么要给你的API编写文档

写代码时,遇到稍复杂的逻辑,我们会发现如果没有注释,一个月后回来发现自己当时写的代码根本不像自己亲生的。再试图熟悉时,可能几个小时就过去了。

同样,对于API来说,如果你不写文档,那么在集成时,你的调用者肯定一边骂,一边尝试各种参数组合。为了让你的调用者有更顺滑的接入体验,每个API的设计者都应该把API文档作为与API的代码一样重要的模块。

好的API文档不光可以方便调用者的接入,更可以方便让你把API更改等信息传递出去,而不是一个一个单独通知你的用户。同时在编写文档时,你也会尝试着以你描述地方式接入,间接做了一次"dogfood"自测。

如果你是面向开发者的API的话,优秀的API文档还可以作为强大的品牌宣传。在卡拉搜索我们花大力气维护我们的文档,同时我们也参考和致敬其它我们用过或者觉得值得夸奖的API文档:

卡拉搜索API文档-用API实现搜索引擎(


转载请注明:http://www.xcqg58.com/bcxx/bcxx/26842151.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了