API 设计中的功能结构

Functionalities structuring in API design

'functionalities structuring',我指的是我们如何组织和协调不同的 API 端点以向客户提供所需的功能。 这里的上下文是 web APIs,供具有 GPS 跟踪功能的手机使用,我假设大多数功能都需要蜂窝网络或 WiFi 连接。

我个人更喜欢 'modular' 方法,其中每个端点主要做一件事,并且它们的集合满足所有要求。当然,您可能需要组合这些端点的某些子集或序列来实现某些功能。 总的来说,我尽量减少端点之间在计算和功能方面的重叠。

另一方面,我知道其他一些人在以下方面更喜欢客户端的便利性(或简单性)而不是模块化:

  1. 如果客户端需要实现一个功能,那么应该存在一个单个API端点来完成,这样客户端只需要一个请求就可以在请求之间以最少的 caching/logic 完成功能。

  2. 对于 GET 端点,如果某些功能涉及多个 levels/kinds 数据,他们更喜欢 [=39= 返回的尽可能多的数据(通常是所有必要的数据) ]单个端点。具有讽刺意味的是,他们可能还需要一个专用端点,用于使用相应的 "highest level" ID 仅检索 "lowest level" 数据。例如,如果 A 对应于 B 的集合,并且每个 B 对应于 C 的集合,那么他们将更喜欢检索所有的直接端点给定 A.

  3. 的相关 C
  4. 在某些极端情况下,他们会要求一个 单一 具有模糊命名(例如 /api/data)的端点 returns 相关基于查询字符串参数的不同组合来自不同底层数据库表(换句话说,不同资源)的数据。

我理解人们喜欢上述便利的目的是: 1. 减少实现功能所需的 API 请求数量; 2. 最大限度地减少客户端的数据缓存和数据逻辑以降低客户端的复杂性,这可以说会导致 'simple' 客户端与服务器的交互得到简化。

不过,我也想知道这样做的成本在长运行的其他方面是否不合理,特别是在服务器端的性能和维护方面API。因此我的问题是:

  1. 构建 API 功能的可靠指南是什么?

  2. 我们如何确定实现移动应用程序功能所需的最佳请求数?当然,如果其他条件都一样,单请求是最好的,但是实现这样的单请求实现通常会在其他方面受到惩罚。

  3. 鉴于客户端请求的数量与服务器端的性能和可维护性之间的竞争API,如何取得平衡以提供合理的设计?

您所问的问题至少分为 API 设计的三个主要领域:

  1. Ontology设计(组织)
  2. Request/Response设计(complexity/performance)
  3. 维护注意事项

根据我的经验(主要来自于在 API 生产方和消费方与非常大的组织合作,并与数百名开发人员就该主题进行交谈),让我们看看每个领域,解决您提出的具体要点...

Ontology设计

在您的设计中有几件事需要考虑,当您说这些时可能暗示:

Overall, I try to minimize the overlapping between endpoints in terms of both computation and functionalities.

这种方法使 API 很容易 被发现 。当您发布 API 供您认识或不认识的其他开发人员使用时(并且可能有或可能没有足够的资源来真正支持),这种模块化 - 使它们变得容易查找和了解 - 创建一种不同类型的 "convenience",从而使您的 API 更容易被采用和重用。

I know some other people much prefer convenience over modularity: 1. if the client needs a functionality, then there should exist a single endpoint in the API which does exactly that...

关于此方法,我想到的最好的 public 示例可能是 Google Analytics Core Reporting API。他们实现了一系列查询字符串参数来构建一个 returns 所请求数据的调用,例如:

https://www.googleapis.com/analytics/v3/data/ga
?ids=ga:12134
&dimensions=ga:browser
&metrics=ga:pageviews
&filters=ga:browser%3D~%5EFirefox
&start-date=2007-01-01
&end-date=2007-12-31

在该示例中,我们通过浏览器查询 Google 分析帐户 12134 的综合浏览量,其中浏览器是 Firefox 在给定日期范围内。

考虑到他们 API 公开的指标、维度、过滤器和细分的数量,他们有一个名为 Dimensions & Metrics Explorer 的工具来帮助开发人员了解如何使用 API .

一种方法使 API 从一开始就更容易被发现和理解。另一个需要更多的支持工作来解释使用 API 的复杂性。上面的 Google API 不是很明显的一件事是某些细分市场和指标不兼容,因此如果您通过一对 key/value 进行调用,您可能不再是能够通过某些其他对。

Request/Response 设计

The context here is APIs for mobile applications.

这仍然很宽泛,更好地定义(如果可能的话)您打算如何使用 "mobile applications" 可以帮助您设计 API。

  1. 您打算完全离线使用它们吗?如果是这样,可能需要 heavy/complete 数据缓存。

  2. 您打算将它们用于低带宽 and/or 高 latency/error-rate 连接场景吗?如果是这样,heavy/complete 数据缓存可能是可取的,但 small/discrete 数据请求也是如此。

for GET endpoints, they often prefer as much data as possible returned by a single endpoint, especially when there are multiple levels/layers of data involved

如果您知道自己只会处于良好的移动连接场景中,或者您可以在这种情况下大量缓存数据(因此可以离线访问或在情况不稳定时访问它),那么这是安全的。

I understand that people preferring convenience aim to reduce the number of API calls necessary to achieve functionalities...

找到一个满意的中间地带的一种方法是在数据密集型调用中实施 paging。例如,可以在指定 'pagesize' 的 GET 中传递查询字符串。因此,10,000 条记录可以在 100 次连续调用中一次返回 100 条,或者在 10 次调用中一次返回 1,000 条。

通过这种方法,您可以设计和发布您的 API,而不必知道您的消费开发人员需要什么。即使上面的分页示例使用了前面引用的 Google API,它仍然可以用在更语义化设计的 API 中。例如,假设您有 GET /customer/phonecalls,您仍然可以将其设计为接受 pagesize 值并连续调用以获取与 customer.[=28= 关联的所有 phonecalls ]

维护

I also wonder if the cost of doing so [reduce the number of API calls necessary to achieve functionalities and to minimize data caching] is not justifiable in the long run, especially for the performance and the maintenance of an API.

这里的关键指导原则是 separation of concerns 如果您的 API 集合将增长到任何显着的复杂性和规模水平。

当您将所有内容捆绑到一个大服务中并且其中的一小部分发生变化时会发生什么?您现在不仅给自己制造了维护难题,而且给 API 消费者带来了麻烦。

"breaking change" 是否真的影响了他们正在使用的 API 部分?他们需要时间和精力来弄清楚这一点。将 API 功能设计为离散的语义服务将使您能够创建路线图并以更易于理解的方式对其进行版本控制。

如需进一步阅读,我建议您查看 Martin Fowler 关于 Microservices Architecture 的文章:

In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms

虽然关于如何在实践中为 "microservices" 设计和构建存在很多争论,但阅读相关内容应该有助于进一步塑造您对所面临的 API 设计决策的思考并准备好参与 "current" 围绕该主题的讨论。