65.9K
CodeProject 正在变化。 阅读更多。
Home

API 抽象是否能加速开发过程?

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2016年10月3日

CPOL

9分钟阅读

viewsIcon

22820

每个软件开发人员都必须面对将大量外部 API 集成到他们的应用程序以增加其用户价值的挑战。这可能会花费大量时间,因为这些 API 通常差异很大。API 抽象承诺提供缓解,但有不同的方法。

无论您是编写移动应用程序、网站、桌面应用程序还是服务器后端,您通常都必须集成多个外部 API。移动应用程序应提供使用任何一个社交网络进行注册和登录的可能性,网站应具有通过社交媒体点赞和评论的按钮,桌面应用程序应与云存储提供商同步数据,理想情况下用户可以选择,并且服务器在新用户成功注册后必须发送电子邮件。

所有这些都需要访问 Facebook、Dropbox、SendGrid 等提供商的 API。

应用程序需要越来越多的 API 集成(图 1)

开发人员的挑战

大多数提供商通过 HTTP 接口公开他们的服务,并通常为不同的平台提供 SDK,这些 SDK 封装了实际的 HTTP 通信,并将其隐藏在函数调用后面。

身份验证本身可能就是开发人员面临的第一个障碍。如果您想通过 API 访问自己的帐户,例如利用短信提供商,通常只需在每个请求中传递一个 API 密钥即可。另一方面,如果开发人员想访问用户的数据,例如使用云存储提供商的常见用例,最常见的是 OAuth 1.0/2.0。OAuth 2.0 是 OAuth 1.0 的演进,它通过强制使用 HTTPS 而不是繁琐的手动签名过程,提供了更高的灵活性和更低的复杂性。

两者的共同点是它们允许应用程序获得对用户数据的授权访问,而用户不必向应用程序公开他们的用户名和密码。相反,用户向服务进行身份验证并授权访问他们的数据,这反过来又使服务授予应用程序访问权限。尽管 OAuth 2.0 与 OAuth 1.0 相比 nowadays 复杂度更低且使用更广泛,但开发人员仍需要理解它,并且在服务器端可以看到不同的实现。此外,仍然有一些知名的服务,例如 Twitter,它们仍然使用 OAuth 1.0。

毫无疑问,最广泛使用的 API 结构概念是 REST(Representational State Transfer),它除了其他方面,还规定资源应该可以通过 URI 以结构化的方式进行唯一寻址和访问。通常通过 HTTP(S) 进行访问,HTTP 方法(GET、POST、PUT、DELETE 等)指示要在资源上执行的操作。虽然许多 API 声称是“RESTful”的,但每个人似乎对 REST 的确切实现方式都有略微不同的看法,这无疑也归因于 REST 更像是一种范例而不是详细标准。这使得 API 结构不一致。

数据格式也不同,最常用的是 JSON 或 XML。JSON 以更紧凑和易读而闻名,XML 被认为更具表现力。尤其是在普遍使用 JavaScript 的 Web 浏览器环境中,JSON 展现了其优势,因为它可以直接映射到 JavaScript 对象。另一方面,XML 允许在没有扩展的情况下使用引用(甚至循环引用)和任意数据类型。开发人员面临的挑战源于一些 API 使用 JSON,而另一些 API 则使用 XML,即使是为了类似的目的。少数 API 允许您选择以任一格式获取数据,但这很少见。

服务返回或接受的实际数据也不同。当涉及用户的出生日期时,可以观察到这种行为的一个简单例子,这是几乎所有社交网络都提供的信息。Facebook 将其作为字符串返回,格式为“MM/DD/YYYY”、“YYYY”或“MM/DD”,具体取决于日期的哪些部分是公开的。

Facebook 使用的日期格式与其他提供商不同(图 2)

Google Plus 使用“YYYY-MM-DD”,Microsoft Live 返回日、月、年三个单独的数字。这意味着开发人员将无法避免涉及此类细节,以便能够将信息规范化为他们在应用程序内部使用的格式。

在文档方面,并非所有服务都做得尽善尽美。有一些服务对它们的 HTTP 接口和 SDK 进行了广泛的文档记录,并包含有用的示例,但也有一些服务的文档只有 handful 过时的示例。只有广泛使用您喜欢的搜索引擎或反复试验才能帮助您找出如何访问或输入所需的信息。

最后但同样重要的是,与这些 API 的通信很少会不出现任何错误。如果用户提供了无效输入,开发人员当然可以确保例如电子邮件地址确实是一个字符串并且格式正确,或者如果不是这种情况则抛出异常。然而,无法在本地验证电子邮件地址是否真实存在,并且电子邮件是否真的可以成功发送到它。这就是为什么能够适当地响应服务器的错误代码和消息很重要。在这里,API 的行为也不同。通常,错误与 HTTP 状态代码没有直接或只有非常不具体的对应关系,这降低了它们的有用性。服务器答案的正文或标头中通常发现的错误描述和机器可读的错误代码特定于 API。

上述问题主要与直接交互 HTTP API 有关,但提供商 SDK 的用户也会遇到其中大多数问题。

API 抽象来救援

最大的问题在于,即使是非常相似的服务,其细节也存在差异。因此,很明显可以将相似的服务抽象成一个共同的接口。即使服务不合作,这也会创建事实上的标准。服务提供的功能越相似,可以抽象的就越多。这有许多优点。开发人员不必深入研究每个服务的文档来学习如何完成特定任务,而是可以只关注一个接口。然后,实现此公共接口的服务可以在代码中统一处理,从而使代码更短、更紧凑且不易出错。

CloudStorage cs;

switch (serviceChoice) {
  case 0: cs = new Dropbox(this, "[ClientID]", "[ClientSecret]"); break;
  case 1: cs = new GoogleDrive(this, "[ClientID]", "[ClientSecret]"); break;
  case 2: cs = new Box(this, "[ClientID]", "[ClientSecret]"); break;
}

InputStream is = cs.download(path);
Android 示例(CloudRail 解决方案)的 API 抽象(图 3)

此外,在当前使用的服务因定价、速率限制等发生变化而失去吸引力时,更容易将一个服务替换为另一个服务。缺点很明显,无法抽象单个服务仅提供的功能,而不会失去统一处理和易于替换的优势。这对于仅使用常见标准功能(例如,云存储提供商的上传和下载)而不要求访问更具体功能的开发人员来说是可以接受的。

有多种此类抽象集成解决方案的提供商,它们大致可分为两类:IPaaS 中间件和抽象 SDK。

集成平台即服务

Kloudless 和 Cloud-Elements 等商业提供商提供一种中间件解决方案,通常称为“集成平台即服务”(IPaaS),它为不同的第三方服务提供统一、抽象的接口。就像第三方服务本身一样,IPaaS 会公开 HTTP 接口和各种平台的 SDK,以便轻松访问该接口。

IPaaS 提供商使用外部中间件(图 4)

这种方法的一个明显好处是开发人员可以在任何平台上使用该抽象,因为即使没有用于所用平台的 SDK,也始终可以直接与 HTTP 接口进行交互。不幸的是,IPaaS 方法也带来了一些缺点。首先,中间件增加了另一个单点故障,降低了整个系统的健壮性。如果 IPaaS 提供商的服务器无法访问,所有集成都会中断。此外,在服务和应用程序之间流动的所有数据都会通过 IPaaS 提供商的服务器,这会导致不必要的流量,尤其是对于云存储提供商,从而导致开发人员最终需要支付额外费用。最后但并非最不重要的是,IPaaS 提供商需要访问未加密的用户数据,否则如何将上述出生日期规范化。这在隐私和数据保护方面可能非常成问题。

抽象 SDK

IPaaS 的一种替代方法是抽象 SDK。它们不作为中间件托管在服务器上,而是作为软件库直接集成到应用程序中。

CloudRail 等服务提供了一个直接集成到应用程序中的单一 SDK(图 5)

至少从硬件方面来说,这使得它们不易受服务中断的影响。数据可以在离开设备并直接发送到服务之前使用 HTTPS 加密,没有绕道。

Spring Social for Java 应用程序使用 Spring 框架,是一个促进社交网络访问的开源项目。虽然它没有将所有社交网络抽象到一个接口中,但它为所有可用服务提供了统一的外观和感觉,并简化了 OAuth 身份验证。

PHP 的 HybridAuth 也专注于社交网络,但提供了一个抽象的通用接口,目前支持 32 种不同的服务。此产品还可以通过插件进一步扩展,身份验证会自动发生,并且它是开源的。

CloudRail 是一家全面的商业解决方案,也提供免费的社区版本。通过为 Android、Java、Node.js、Swift 和 Objective-C 提供抽象 SDK,开发人员可以集成来自多个类别的服务。目前,这些类别包括云存储、社交网络、短信、电子邮件、支付和兴趣点。该解决方案具有广泛的文档、抽象的 API 和简单的身份验证。此外,CloudRail 提供了一项名为“API 更改管理”的功能,可为开发人员提供自动化的 API 监控和通知,以防集成的一个 API 发生更改或变得不可用,例如 Dropbox 宣布关闭其 v1 API。由于抽象,只需更新 SDK 即可,无需更改代码。

// let social = Twitter(clientID: "[clientID]", clientSecret: "[clientSecret]")
let social = Facebook(clientID: "[clientID]", clientSecret: "[clientSecret]")
do{
  try social.postUpdateWithContent("CloudRail is awesome!!!")
} catch let error{
  print("An error: \(error)")
}
使用 CloudRail 的 Swift SDK 发布到社交网络(图 6)

摘要

如果您必须集成许多不同的 API,由于它们在身份验证、结构、数据格式、文档和错误报告方面的差异,您将面临一系列挑战。抽象可以是一种补救措施,有托管解决方案和直接集成到应用程序中的库。前者以平台独立性取胜,后者提供更好的可扩展性、健壮性和数据安全性。API 提供商最终不太可能就一个所有人都遵守的通用标准达成一致。为了在功能上区分自己的产品与竞争对手的产品,差异化需求太大了,而标准会阻碍这一点。鉴于我们可以预见市场上 API 越来越多,“统一访问”变得越来越重要,这使得上述解决方案越来越相关。

© . All rights reserved.