两个独立的应用程序需要中介程序才能相互通信。 因此,开发人员经常建立桥梁-应用程序编程接口-来允许一个系统访问另一个系统的信息或功能。
为了快速,大规模地集成应用程序,使用协议和/或规范来定义通过导线传递的消息的语义和语法的API。 这些规范构成了API体系结构。
随着时间的流逝,已经发布了不同的API架构样式。 它们每个都有自己的标准化数据交换模式。 选择的余地引发了关于哪种建筑风格最好的争论。
> API styles over time, Source: Rob Crowley
如今,许多API使用者将REST称为" REST和平",并为GraphQL欢呼,而十年前,REST取代SOAP成为赢家,这是一个相反的故事。 这些观点的问题在于,他们只是一方面选择一种技术,而不是考虑其实际属性和特性如何与当前情况相匹配。
在本文中,我们将保持客观,并按外观顺序讨论四种主要的API样式,比较它们的优缺点,并重点介绍每种情况下最适合的情况。
> Four major API styles compared
远程过程调用是一种允许在不同上下文中远程执行功能的规范。 RPC扩展了本地过程调用的概念,但将其放在HTTP API的上下文中。
最初的XML-RPC存在问题,因为很难确保XML有效负载的数据类型。 因此,后来RPC API开始使用更具体的JSON-RPC规范,该规范被认为是SOAP的更简单替代方案。 gRPC是google在2015年开发的最新RPC版本。gRPC可插拔支持负载平衡,跟踪,运行状况检查和身份验证,非常适合连接微服务。
客户端调用远程过程,将参数和其他信息序列化为消息,然后将消息发送到服务器。 在接收到消息时,服务器反序列化其内容,执行所请求的操作,然后将结果发送回客户端。 服务器存根和客户端存根负责参数的序列化和反序列化。
> Remote Procedure Calling Mechanism, Source: Guru99
简单直接的互动。 RPC使用GET来获取信息,并使用POST进行其他所有操作。 服务器与客户端之间的交互机制归结为调用端点并获得响应。
易于添加的功能。 如果对API提出了新要求,我们可以轻松添加另一个执行此要求的端点:1)编写一个新函数并将其扔到端点后面; 2)现在,客户可以访问该端点并获取符合设置要求的信息 。
高性能。 轻量级有效负载在网络上变得容易,可提供高性能,这对于共享服务器和在工作站网络上执行的并行计算非常重要。 RPC能够优化网络层,并通过每天在不同服务之间发送大量消息来使其变得非常高效。
与底层系统紧密耦合。 API的抽象级别有助于其可重用性。 它与基础系统越紧密,对其他系统的可重用性就越差。 RPC与基础系统的紧密耦合不允许在系统功能和外部API之间建立抽象层。 这很容易引起安全问题,因为很容易将有关基础系统的实施细节泄漏到API中。 RPC的紧密耦合使得可伸缩性要求和松散耦合的团队难以实现。 因此,客户端要么担心调用特定端点的任何可能的副作用,要么尝试弄清楚要调用的端点,因为它不了解服务器如何命名其功能。
发现性低。 在RPC中,无法对API进行自省或发送请求,也无法根据其请求开始理解要调用的函数。
功能爆炸。 创建新功能非常容易。 因此,我们不用编辑现有功能,而是创建新功能,最后添加大量难以理解的重叠功能。
RPC模式在80年代左右开始使用,但这并不会自动使其过时。 诸如Google,Facebook(Apache Thrift)和Twitch(Twirp)之类的大公司正在内部使用RPC高性能变量来执行非常高性能,低开销的消息传递。 他们庞大的微服务系统要求内部通信在安排短消息时保持清晰。
命令API。 RPC是将命令发送到远程系统的正确选择。 例如,Slack API非常注重命令:加入频道,离开频道,发送消息。 因此,Slack API的设计人员以类似于RPC的样式对其进行了建模,使其小巧,紧凑且易于使用。
内部微服务的客户特定API。 由于在单个提供商和使用者之间进行了直接集成,我们不想像REST API那样花费大量时间通过网络传输大量元数据。 凭借高消息速率和消息性能,gRPC和Twirp是微服务的强大案例。 在后台使用HTTP 2,gRPC能够优化网络层并使其非常高效,每天在不同服务之间发送大量消息。 但是,如果您不是要着眼于提高网络性能,而是要在发布高度独特的微服务的团队之间建立稳定的API联系,REST将确保这一点。
SOAP是XML格式的高度标准化的Web通信协议。 SOAP在Microsoft于XML-RPC发行一年后发布,从中继承了很多东西。 当REST紧随其后时,它们首次并行使用,但很快REST赢得了流行度竞赛。
XML数据格式拖累了许多形式。 配合庞大的消息结构,它使SOAP成为最冗长的API样式。
SOAP消息包括:
· 包含请求或响应的正文
· 标头(如果消息必须确定任何具体要求或额外要求),以及
· 故障通知在整个请求处理过程中可能发生的任何错误。
> An example of the SOAP message. Source: IBM
SOAP API逻辑以Web服务描述语言(WSDL)编写。 该API描述语言定义了端点并描述了可以执行的所有过程。 这允许不同的编程语言和IDE快速建立通信。
SOAP支持有状态和无状态消息传递。 在有状态的情况下,服务器存储接收到的信息可能非常重。 但这对于涉及多方和复杂交易的操作是合理的。
与语言和平台无关。 创建基于Web的服务的内置功能允许SOAP处理通信并做出与语言和平台无关的响应。
绑定到各种传输协议。 SOAP在传输协议方面很灵活,可以适应多种情况。
内置错误处理。 SOAP API规范允许返回带有错误代码及其说明的Retry XML消息。
许多安全扩展。 SOAP与WS-Security协议集成,可满足企业级事务质量。 它在事务内部提供隐私和完整性,同时允许在消息级别进行加密。
> SOAP message-level security: authentication data in the header element and encrypted body
如今,由于多种原因,许多开发人员对必须集成SOAP API的想法感到不安。
仅XML。 SOAP消息包含大量元数据,并且仅支持请求和响应的详细XML结构。
重量级的。 由于XML文件的大小,SOAP服务需要很大的带宽。
狭义的知识。 构建SOAP API服务器需要深入了解所有涉及的协议及其严格的规则。
乏味的消息更新。 需要额外的努力来添加或删除消息属性,严格的SOAP模式会减慢采用速度。
目前,SOAP体系结构最常用于企业内部或与其信任的合作伙伴的内部集成。
高度安全的数据传输。 SOAP的严格结构,安全性和授权功能使其成为执行API与客户端之间的正式软件合同,同时又遵守API提供者与API使用者之间的合法合同的最合适的选择。 这就是为什么金融组织和其他公司用户选择SOAP的原因。
REST是一种不言自明的API架构样式,由一组架构约束定义,旨在供许多API使用者广泛采用。
当今最常见的API样式最初是由Roy Fielding于2000年在其博士论文中描述的。 REST使服务器端数据可用,以简单格式(通常为JSON和XML)表示它。
REST的定义不像SOAP那样严格。 RESTful体系结构应遵守六个体系结构约束:
· 统一接口:无论设备或应用程序类型如何,都可以采用统一的方式与给定服务器进行交互
· 无状态:处理请求本身所包含的请求的必要状态,并且服务器不存储与会话相关的任何内容
· 快取
· 客户端-服务器体系结构:允许双方的独立发展
· 应用程序的分层系统
· 服务器向客户端提供可执行代码的能力
实际上,某些服务仅在一定程度上是RESTful的。 它们以RPC样式为核心,将较大的服务分解为资源,并有效地使用HTTP基础结构。 但是关键部分是使用超媒体(又称HATEOAS),是超文本作为应用程序状态引擎的缩写。 基本上,这意味着REST API在每个响应中都提供元数据链接,该元数据链接到有关如何使用该API的所有相关信息。 这样便可以使客户端和服务器脱钩。 结果,API提供者和API使用者都可以独立发展,而不会阻碍他们的交流。
> Richardson Maturity Model as a goalpost to achieving truly complete and useful APIs, Source: Krist
" HATEOAS是REST的关键功能。 真正使REST成为REST的原因。 由于大多数人不使用HATEOAS,因此实际上是在使用HTTP RPC,"这是Reddit上表达的一些激进观点。 实际上,HATEOAS是REST的最成熟版本。 但是,要实现比当今通常使用和构建的API客户端更为先进和智能的API客户端要困难得多。 因此,即使是当今非常好的REST API也不一定总是做到这一点。 这就是为什么HATEOAS主要用作RESTful API设计的长期开发的愿景。
当服务实现REST的某些功能和RPC的某些功能时,在REST和RPC之间确实可能存在一个灰色区域。 REST基于资源或名词,而不是基于动作或动词。
> Opposing operations in verb-centric RPC to the ones in noun-centric REST
在REST中,使用GET,POST,PUT,DELETE,OPTIONS和PATCH等HTTP方法完成操作。
> Source: Thomas Davis
客户端和服务器解耦。 REST尽可能使客户端和服务器脱钩,与RPC相比,REST可以提供更好的抽象性。 具有抽象级别的系统能够封装其详细信息,以更好地标识和维持其属性。 这使得REST API足够灵活,可以随着时间的推移而发展,同时保持稳定的系统。
可发现性。 客户端与服务器之间的通信描述了所有内容,因此不需要外部文档即可了解如何与REST API进行交互。
缓存友好。 REST重用了许多HTTP工具,是唯一一种可以在HTTP级别上缓存数据的样式。 相反,在任何其他API上进行缓存实现将需要配置其他缓存模块。
多种格式支持。 支持多种格式用于存储和交换数据的能力是REST当前成为构建公共API的主要选择的原因之一。
没有单一的REST结构。 没有建立REST API的正确方法。 如何对资源进行建模以及要对哪些资源进行建模将取决于每种情况。 这使得REST在理论上很简单,但在实践中却很困难。
大负载。 REST返回很多丰富的元数据,以便客户端可以仅从响应中了解有关应用程序状态的所有必要信息。 对于具有大量带宽容量的大型网络管道而言,这种聊天状态并不重要。 但这并非总是如此。 这是Facebook在2012年提出GraphQL样式的关键驱动因素。
过度获取和不足获取问题。 REST响应包含的数据过多或不足,通常会导致需要另一个请求。
管理API。 专注于管理系统中对象并面向许多使用者的API是最常见的API类型。 REST帮助此类API具有强大的可发现性,良好的文档编制,并且非常适合此对象模型。
简单的资源驱动型应用程序。 REST是一种非常有用的方法,用于连接不需要查询灵活性的资源驱动型应用。
它需要多次调用REST API才能返回所需的人员。 因此,GraphQL被发明为改变游戏规则的人。
GraphQL是一种语法,描述了如何进行精确的数据请求。 对于具有许多相互引用的复杂实体的应用程序数据模型而言,实现GraphQL是值得的。
> How to retrieve only the needed data from the GraphQL endpoint, Source: Mohit Tikoo
如今,GraphQL生态系统正在通过库和强大的工具(如Apollo,GraphiQL和GraphQL Explorer)进行扩展。
GraphQL从构建模式开始,该模式是对您可以在GraphQL API中进行的所有查询及其返回的所有类型的描述。 模式构建非常困难,因为它需要使用模式定义语言(SDL)进行强类型化。
在查询之前具有架构,客户端可以验证其查询,以确保服务器能够对其进行响应。 在到达后端应用程序时,将针对整个模式解释GraphQL操作,并使用前端应用程序的数据进行解析。 该API向服务器发送一个庞大的查询后,会返回一个JSON响应,其中包含我们所需数据的确切形状。
> Query execution in GraphQL, Source: Jonas Helfer
除了RESTful CRUD操作之外,GraphQL的订阅还允许来自服务器的实时通知。
键入的架构。 GraphQL会提前发布其功能,从而提高其可发现性。 通过将客户端指向GraphQL API,我们可以找出可用的查询。
非常适合类似图形的数据。 数据关系很深,但不适合平面数据。
没有版本控制。 版本控制的最佳做法是根本不对API进行版本控制。
REST提供了多个API版本,而GraphQL使用的是一个不断发展的版本,它可以持续访问新功能,并有助于提供更清洁,更可维护的服务器代码。
详细的错误消息。 GraphQL以类似于SOAP的方式提供发生错误的详细信息。 它的错误消息包括所有解析器,并引用发生故障时的确切查询部分。
灵活的权限。 GraphQL允许选择性地公开某些功能,同时保留私人信息。 同时,REST体系结构不会部分显示数据。 全部或全无。
性能问题。 GraphQL权衡了复杂性。 一个请求中的嵌套字段太多会导致系统过载。 因此,对于复杂的查询,REST仍然是更好的选择。
缓存复杂度。 由于GraphQL不再使用HTTP缓存语义,因此需要自定义缓存工作。
很多预开发教育。 由于没有足够的时间来了解GraphQL利基操作和SDL,因此许多项目决定采用众所周知的REST路径。
移动API。 在这种情况下,网络性能和单个消息有效负载优化很重要。 因此,GraphQL为移动设备提供了更有效的数据加载。
复杂的系统和微服务。 GraphQL能够隐藏其API背后的多个系统集成的复杂性。 从多个位置聚合数据,它将它们合并为一个全局模式。 这对于随时间推移而扩展的旧式基础结构或第三方API尤其重要。
每个API项目都有不同的要求和需求。 通常,架构选择取决于
· 使用的编程语言
· 您正在开发的环境,以及
· 您必须保留的人力和财力资源。
知道了每种设计风格的所有权衡之后,API设计人员可以选择最适合该项目的一种。
由于RPC紧密耦合,因此可用于内部微服务,但对于强大的外部API或API服务而言,它不是一种选择。
SOAP很麻烦,但是其丰富的安全功能对于计费操作,预订系统和付款仍然是不可替代的。
REST具有API的最高抽象度和最佳建模。 但是在网络和聊天环境中,这往往会比较沉重-如果您正在使用移动设备,这将是不利的一面。
GraphQL在数据获取方面迈出了一大步,但并不是每个人都有足够的时间和精力来掌握它。
归根结底,尝试一些具有特定样式的小型用例,并查看它是否适合您的用例并解决您的问题是有意义的。 如果可以,请尝试扩展并查看它是否适合更多用例。
最初发布于AltexSoft技术博客"比较API体系结构样式:SOAP vs REST vs GraphQL vs RPC"
(本文翻译自Sanjeet Chatterjee的文章《Comparing API Architectural Styles: SOAP vs REST vs GraphQL vs RPC》,参考:https://levelup.gitconnected.com/comparing-api-architectural-styles-soap-vs-rest-vs-graphql-vs-rpc-84a3720adefa)