设想一下,您在网上下单买了一张需要自行组装的桌子,但到货后发现包裹里没有组装说明。您知道最终成品的外观是什么样子,但不知道如何动手把各个部件组装起来。设计不善的 API 也会给身为实际使用者的开发者带来类似的负面体验。设计良好的 API 则能为身为实际使用者的开发者提供轻松便利的查找、探索、访问和使用体验。在某些情况下,优质 API 甚至能让身为实际使用者的开发者激发新创意,发现新的应用场景。
有一些方法可以改进 API 设计,比如遵循 RESTful 实践。但我们一次又一次地发现,客户的 API 编程无意中给使用者造成了一些细节上的不便。为了帮您避开这些陷阱,我们整理出开发者在创建 API 时最常犯的六种错误,并为您提供妥善处理这些细节的指导。
1. 由内而外的思维模式与由外而内的思维模式
面面俱到通常就等同于博而不精,这个道理同样适用于 API 领域。客户使用 API 的目的是借助专门的解决方案来简化工作、提高工作效率。如果有某种 API 能更好地满足其需求,他们就会放弃您的 API,转而选择另外那种。因此请您务必清晰了解客户需要什么才能更好地处理其工作,随后以满足这些需求为目标构建 API。换句话说,最初应采用由外而内的思维模式,而非由内而外的思维模式。两种思维模式的具体含义是:
由内而外表示以您希望公开的内部系统或服务为核心,围绕这样的核心设计 API。
由外而内表示以您希望打造的客户体验为核心,围绕它来设计 API。阅读《API 产品思维模式》(The API Product Mindset) 电子书,进一步了解由外而内的思维模式。
这种做法的第一步是从客户处收集信息,包括作为最终使用者的内部开发者以及外部客户,还要了解他们的应用场景。询问他们构建的应用,他们的痛点,以及哪些做法可以帮助他们更顺畅或轻松地进行开发。记下他们最重要的应用场景,创建示例 API 响应,确保精准提供他们在每个应用场景中所需要的数据。在测试时,注意载荷之间的重叠,并调整设计,使其广泛适用于常用或类似的应用场景。
如果您无法与客户沟通,比如您没有直接联系客户的权限、客户没有时间或不清楚自己的确切需求,那么最好的方法是想象您会用自己的 API 构建什么样的应用。放宽视野,放飞创意。您必定不想为还没发布的“雾件”设计 API,但若能在设计时放宽视野,那么未来您可能只需小幅调整就能轻松满足客户需求。例如,下图展示了Google 地图提供的 API。
即便不深入研究文档,通过“自动补全”或“地址验证”这样的名词也能清晰勾勒出 API 的用途以及同客户应用场景的潜在契合度。
2. 构建出对用户而言过于复杂的 API
客户使用 API 的初衷是避开错综复杂的编程难题,专注于他们熟谙的领域。如果他们觉得使用您的 API 就需要学习一套全新的系统或编程语言,那么您的 API 就不够契合他们的需求,他们很可能另择佳选。您的团队要尽力打造出足够强大、足够巧妙的 API,从而满足客户的需求,同时也要保证足够简单易用,确保无论 API 所处理的任务实际上有多复杂,用户都丝毫感受不到。例如,假设您知道客户要使用您的 API 为其消费者显示近期新开饭店和高评分披萨店的信息,那么如果您为其提供下面这种简单的 API 调用,就会对他们大有帮助:
GET /restaurants?location=Austin&category=Pizzeria&open=true&sort=-priority,created_at
若要评估您的 API 设计是否足够简单易用,不妨假设您在从零开始构建整个系统,如果您有可信的客户愿意帮忙,也可以请他们进行测试并分享结果。如果您可以顺畅无阻地完成工作流,那就说明 API 设计比较理想。反之,如果您发现由于编码时以系统复杂性问题为中心,造成使用体验不尽人意,那么可以尝试重构。如果您确定 API 没有任何令人困惑之处,契合客户需求或者能在需要更改时轻松更新,那么您的 API 就准备就绪了。
3. 创建的 API 过于“吵闹”,调用次数太多
大量的网络调用会拖慢工作流程,也会造成过高的连接开销,进而增加运营成本。因此务必尽量减少 API 调用次数。
为实现这一目标,关键就在于由外而内的设计:简易性。设法减少客户在应用工作流中必须执行的 API 调用次数。举例来说,假设客户在构建移动应用,他们往往需要尽可能减少网络流量,从而降低耗电量,那么对于这些客户,将 API 调用次数从数十次减少到几次也会意义非凡。
构建由数据驱动的独特微服务,还是简化 API 用法?您不必艰难抉择,完全可以两者兼顾:提供针对特定数据类型微调的 API,以及以通用或客户特定界面为中心的“体验式 API”(专为提升用户体验而设计的 API。点击此处查看有关体验式 API 的理论讨论)。这些体验式 API 将多个较小的网域并入一个端点,可让您的客户(特别是构建界面的客户)轻松而快捷地呈现其屏幕。
这方面的另一种选择是使用 GraphQL 等语言来支持此类定制化。通常情况下,您应该避免为有可能用到的每一个屏幕构建一个不重复端点,仅为主页和用户帐号信息等通用屏幕采取这种方案,对于 API 使用者来说,这会带来很大的不同。
4. 未提供灵活性
即便您遵循了上文提到的所有步骤,仍有可能会遇到一些并不适合您精心设计的载荷的边缘情况。或许您的客户需要在一个结果页面中呈现比平常更多的数据,也或许是载荷的数据量远超过其应用需要的数据量。全能型解决方案当然并不存在,但您肯定不想给人留下您构建的 API 处处让人束手束脚的印象。您可以考虑下面这 3 种简单的方案,提高您端点的灵活性。
过滤响应属性:您可以使用查询参数实现排序和分页,也可以使用 GraphQL,这种编程语言以原生方式实现了这些细节。通过为客户提供仅请求所需属性的选项,即可保证他们不必在充斥着大量不必要数据的内容中苦苦寻找所需信息。
例如,假设您的一些客户仅需要标题、作者和热销榜单排名,应该支持他们通过一个查询字符串参数精准检索这些数据。
GET /books?fields=title,author,ranking
排序及分页功能。通常情况下,您并不希望确保 API 响应中的对象顺序,因为数据源逻辑或特性的细微变化就有可能在某个点改变排列顺序。但有些时候,您的客户可能希望按特定字段排序。如果您能为其提供相应的排序和分页选项,即可打造出高效的 API,满足他们仅获得排名靠前的少数结果的需求。例如,
Spotify API 支持利用简单的 offset 和 limit 参数设置实现分页。文档中一个端点的示例形式如下:
使用 GraphQL 等成熟的组合工具:客户数据需求千差万别,因此您应该为他们提供即时组合的能力,这样他们就能根据自己的需求构建数据组合,而不必受限于单一数据类型或数据字段的预设组合。使用 GraphQL 时,甚至不必构建体验式 API,但如果无法使用此类工具,您可以使用“expand”等查询字符串参数选项,创建这些较为复杂的查询。下面这个示例响应展示了包含内嵌属性的公司资源集合
"data": [
{
"CompanyUid": "27e9cf71-fca4",
"name": "ABCCo",
"status": "Active",
"_embedded": {
"organization": {
"CompanyUid": "27e9cf71-fca4",
"name": "ABCCo",
"type": "Company",
"taxId": "0123",
"city": "Portland",
"notes": ""
}
}
}
]
5. 设计不易理解
设计 API 时,要确保其清晰易懂。虽然 API 的设计目标是实现计算机与计算机之间的交互,但最初使用 API 的总是人类,其文档的第一部分总是 API 合约。开发者往往先研究您的载荷设计,然后才会深入研究文档。观察式研究表明,开发者有超过 51% 的时间用在编辑器和客户端中,仅有大约 18% 的时间用于研究参考文档。
例如,下面这段载荷代码不太容易理解,因为其中使用的是“id”,而非属性名称。代码中使用的“data”这个属性名称也无法表明任何意义,只是 JSON 设计中的一个工件而已。如果能在载荷中多用一些字节来指定属性名称,就能显著减少使用者在初期的困惑,也能让您的 API 更快地得到采用。在阅读载荷时,请注意冒号左侧的用户 ID(在其他比较理想的 JSON 示例中,这个位置放的是属性名称)有多让人困惑。
"{id-a}":
{ "data":
[
{
"AirportCode": "LAX",
"AirportName": "Los Angeles",
"From": "LAX",
"To": "Austin",
"departure": "2014-07-15T15:11:25+0000",
"arrival": "2014-07-15T16:31:25+0000"
}
…// More data
]
},
我们认为,这样的 JSON 代码更难理解。如果您希望避免数据描述措辞中的歧义,应该简化载荷,如果有任何标签存在不止一种解读方式,应对其进行调整,确保其更加清晰易懂。下面这个示例响应来自 aviationstack API 的 Airlines 端点。请注意属性名称多么清晰地解释了预期结果,同时保持了简单的 JSON 结构。
"data": [
{
"airline_name": "American Airlines",
"iata_code": "AA",
"iata_prefix_accounting": "1",
"icao_code": "AAL",
"callsign": "AMERICAN",
"type": "scheduled",
"status": "active",
"fleet_size": "963",
"fleet_average_age": "10.9",
"date_founded": "1934",
"hub_code": "DFW",
"country_name": "United States",
"country_iso2": "US"
},
[...]
]
6. 了解何时可以不遵守 RESTful 规则
坚持遵守 RESTful 的基本规则(例如使用正确的 HTTP 动词、状态代码和基于无状态资源的接口)能给客户带来更便利的体验,让他们不必去学习一整套新的专门词汇,但请注意,您的目标是帮助他们完成工作。如果您把 RESTful 设计原则放在用户体验之前,那有可能会违背初衷。
您的目标应该是帮助客户利用您的数据取得成功,而且是尽可能快速、便捷地达成这一目标。因此有些时候,您可能要违背一些 REST“规则”,从而提供更简单、更精致的接口。不过您应该在自己的所有 API 中采用一致的设计方案,也要在文档中清晰地说明不同寻常或不同于标准的细节。
总结
Google Cloud 的原生 API 管理平台 Apigee 可帮您构建、管理和保护 API,并且支持任何应用场景、规模和环境。
文章信息
相关推荐
