我个人更喜欢更“模块化”的方法,其中每个端点主要完成一件事,并且它们的集合满足所有要求.当然,您可能需要组合这些端点的一些子集或序列以实现某些功能.总的来说,我尝试在计算和功能方面最小化端点之间的重叠.
另一方面,我知道其他一些人更喜欢客户端方便(或简单)而不是模块化,方法如下:
>如果客户端需要实现某个功能,那么应该存在一个完全相同的API端点,这样客户端只需要一个请求即可在请求之间以最小的缓存/逻辑来实现功能.
>对于GET端点,如果某些功能涉及多个级别/种类的数据,则他们更喜欢单个端点返回的尽可能多的数据(通常是所有必需的数据).具有讽刺意味的是,他们可能还需要一个专用端点,用于使用相应的“最高级别”ID检索“最低级别”数据.例如,如果A对应于B的集合,并且每个B对应于C的集合,那么他们将更喜欢直接端点,其检索给定A的所有相关C.
>在某些极端情况下,他们将要求具有模糊命名的单个端点(例如/ api / data),其基于查询字符串参数的不同组合返回来自不同底层DB表(换句话说,不同资源)的相关数据.
据我所知,人们更喜欢上述便利,目的是:1.减少履行功能所需的API请求数量; 2.最小化客户端的数据缓存和数据逻辑,以降低客户端的复杂性,这可以说是一个“简单”的客户端,简化了与服务器的交互.
但是,我也想知道从长远来看这样做的成本是否在其他方面是不合理的,特别是在服务器端API的性能和维护方面.因此我的问题:
>构建API功能的经过验证的指南是什么?
>我们如何确定在移动应用中实现功能所需的最佳请求数量?当然,如果所有其他条件相同,单个请求是最好的,但实现这样的单一请求实现通常会在其他方面带来惩罚.
>鉴于客户端请求的数量与服务器端API的性能和可维护性之间存在争议,为实现合理的设计,有哪些方法可以达到平衡?
解决方法
>本体设计(组织)
>请求/响应设计(复杂性/性能)
>维护注意事项
根据我的经验(主要是与API生产和消费方面的大型组织合作以及与数百名开发人员讨论该主题),让我们看看每个领域,解决您提出的具体问题……
本体设计
在您的设计中需要考虑几件事情,当您说:
Overall,I try to minimize the overlapping between endpoints in terms of both computation and functionalities.
这种方法使API易于发现.如果您正在发布API供其他开发人员使用而您可能知道或可能不知道(并且可能有也可能没有足够的资源来真正支持),这种模块化 – 使它们易于查找和了解 – 创建一种不同的“便利”,使您更容易采用和重用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…
这种方法的最佳公共示例可能是Google Analytics Core Reporting API.它们实现了一系列查询字符串参数来构建一个返回所请求数据的调用,例如:
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 Analytics帐户12134的浏览量,其中broswer是给定日期范围的Firefox.
考虑到API公开的指标,维度,过滤器和细分的数量,他们有一个名为Dimensions & Metrics Explorer的工具来帮助开发人员了解如何使用API.
一种方法从一开始就使API可被发现并且更容易理解.另一个需要更多的支持工作来解释消费API的复杂性.上面的Google API并不是很明显的一点是,某些细分和指标是不兼容的,因此如果您通过一个键/值对进行调用,则可能无法再通过某些其他对.
请求/响应设计
The context here is APIs for mobile applications.
这仍然非常广泛,更好地定义(如果可能)您打算如何使用“移动应用程序”可以帮助您设计API.
>你打算让他们完全脱机使用吗?如果是这样,则可能需要繁重/完整的数据缓存.
>您是否打算将它们用于低带宽和/或高延迟/错误率连接方案?如果是这样,可能需要繁重/完整的数据缓存,但小/离散数据请求也是如此.
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.例如,可以在GET中传递查询字符串,指定“pagesize”.因此,可以在100次连续呼叫中一次返回100个记录100个,或者在10个呼叫中一次返回1,000个记录.
使用这种方法,您可以设计和发布API,而无需了解您的开发人员需要什么.即使上面的分页示例使用前面引用的Google API,它仍然可以在更加语义设计的API中使用.例如,假设您有GET / customer / phonecalls,您仍然可以将其设计为接受pagesize值并进行连续调用以获得与客户关联的所有电话呼叫.
保养
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.
如果您的API集合将增长到任何重要的复杂性和规模,那么这里的关键指导原则是separation of concerns.
如果将所有内容捆绑在一起构成一个大型服务并且其中的一小部分发生变化,会发生什么?您现在不仅要在您身边创建维护问题,还要为您的API使用者创建问题.
这种“突破性变化”真的会影响他们使用的API部分吗?需要时间和精力才能弄清楚这一点.将API功能设计为离散的语义服务将允许您创建路线图并以更易理解的方式对其进行版本化.
为了进一步阅读,我建议在Microservices Architecture查看Martin Fowler的着作:
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
虽然关于如何在实践中设计和构建“微服务”存在很多争论,但阅读这些内容应该有助于进一步塑造您对所面临的API设计决策的思考,并为您准备参与“当前”讨论做好准备话题.