原文作者:NGINX
原文链接:概念回顾:REST API 和 GraphQL
转载来源:NGINX 开源社区
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn
REST API 和 GraphQL 作为两种主流的 API 模型,各有其优点和问题。阅读本文,深入了解两种 API 模型的基础概念及区别和联系。
REST API 是一种应用编程接口 (API),遵循表征状态转移 (REST) 模型,支持两个系统(客户端和服务器)之间通过互联网等网络进行数据表示和通信。REST API 支持在内部和第三方应用之间执行信息交换,并允许企业将多个端点集成到其应用生态系统中。
注:严格来说,REST 指的是模型,而不是作为形容词来描述某 API 遵循该模型,后者的专有名词是“RESTful API”。但“REST API”是更常见的用法,因此本文也使用了这一用法。
API 是一组定义、规则和协议,用于规范信息使用者(客户端)和信息提供者(服务器)之间的数据交换。换言之,API 是访问信息(即在线和 Web 应用提供的数据资源)的用户(人或软件)之间的一种通信方式。当开发人员为一款应用创建 API 并将其暴露到互联网上时,其他应用就可以以编程方式与该应用通信。
API 能够确保信息的可复用性和可访问性,从而帮助企业做出数据驱动型决策,并有助于开发人员简化工作。开发人员可通过调用现有应用的 API 中的函数,将功能集成到其应用中,而不必浪费时间来复制现有应用的功能。
如前所述,REST 是指“表征状态转移(representational state transfer)”,是由计算机科学家 Roy Fielding 于 2000 年创建的一种架构风格。REST 为开发人员提供了灵活性,因而非常适合连接微服务架构中的应用。
REST 定义了以下 6 个约束条件,应用和 API 必须遵守这些条件才能被视为 RESTful:
统一接口
“客户端-服务器”架构
无状态
分层系统
可缓存性
按需编码
统一接口可简化整个系统架构,并提高交互可视性。它还有具体的要求说明,以确保以标准形式传输信息。
以下 4 个约束条件可确保 REST 接口的统一:
每个资源都有一个唯一标识符(例如 URI),并且消息中的资源表示(representation)与服务器的内部表示不同
资源表示为客户端修改或删除资源状态提供了足够的信息
每条消息都包含足够的信息来描述资源处理方式
服务器使用超链接向客户端告知可用资源,因此客户端无需了解服务器内部信息
“客户端-服务器”架构由客户端(client)、服务器(sever)和资源(resources)组成。将用户界面(由客户端控制)与数据存储(由服务器控制)分离开来,意味着客户端和服务器组件可自主演进。它还简化了客户端用户界面在多个平台上的可移植性和服务器的可扩展性。
在互联网上,“客户端-服务器”的交互通过 HTTP 实现。
在“客户端-服务器”通信中,“无状态”意味着服务器不会存储有关客户端或与客户端所建会话(session)的任何信息。客户端必须确保服务器能够独立地理解每条消息中与会话相关信息的表示(representation),且无需从之前的消息中获取任何上下文。这有助于减轻服务器负载,从而提高大容量应用的性能。
客户端不需要知道(通常也无法判断)它们是直接连接到服务器还是连接到反向代理或负载均衡器等中介。中介服务器有助于提高可扩展性,并可用于处理安全问题,这样服务器就只负责处理业务逻辑。
HTTP 客户端和中介组件可以缓存服务器响应,以减少服务器上的负载,并提高向最终用户传递数据的速度。服务器必须指明响应(response)是可缓存的还是不可缓存的,后者可确保对后续最终用户请求的响应是正确且最新的(而非可能“过期”的数据)。由于客户端访问资源的 URL 是唯一标识符,因此客户端能够从“资源”的层面确定缓存内容。
按需编码是指服务器可以发送可执行代码以暂时扩展或自定义客户端功能,而无需客户端自己实现这些功能。“按需编码”这一约束条件不是必需的。
REST 中最重要的数据表示或抽象是“资源(resource)”。REST 资源可以是任何类型的抽象信息,包括数字文档和非数字对象。资源在任何特定时间的状态称为“资源表示(resource representation)”。
资源表示包括以下三个部分:
数据
元数据
超媒体链接
REST API 由一组可通过唯一 URL 访问的互联资源(或其“资源模型(resource model)”)组成。客户端可以通过链接到响应中的相关资源和 URI 来实现灵活的功能。通常,对 REST API 的请求以 HTTP GET 请求的形式发送;服务器通常将其响应格式化为 JSON。
下列 HTTP 请求方法用于以指定方式处理资源:
GET — 加载资源
POST — 创建新资源
PUT — 修改现有资源
DELETE — 删除资源
在 REST 架构风格中,资源标识符(resource identifier)唯一地指定了参与“客户端-服务器”交互的每个资源。
“媒体类型(media type)”或数据格式表示(representation of data format)定义了应如何处理资源。在 REST API 中,所有媒体类型都基于 JSON,并均为超媒体(有时称为“超文本”,但与超文本略有不同)。“超媒体”是指带有其他媒体链接的任何内容。 超媒体即应用状态引擎 (Hypermedia as the Engine of Application State,即 HATEOAS) 是 REST 架构的独特之处。
注:Roy Fielding 指出,要将 API 视为 REST API,则必须使用超媒体。然而,如今许多 API 设计人员经常将其 API 称为“REST[ful]”,尽管他们不使用超媒体/超文本。
资源表示旨在实现自描述(self-descriptive),这意味着 API 在其自己的上下文中进行自我表述。借助自描述表示,客户端无需知道资源所属类别,而是根据与资源相关的媒体类型进行操作。
如今,大多数企业都使用内部开发的 API 和第三方 API 在提供基本功能、创新功能和关键功能的应用之间进行通信。这些 API 大多是 REST API,因为 REST 规定的特定通信标准支持执行安全、高效和可靠的信息交换。REST API 也可与任何协议配合使用。
REST API 也具有安全性,因为 RESTful Web 服务会在发送响应之前对请求进行身份验证。为了验证用户身份,REST API 使用 HTTP 身份验证(同时使用 Basic 令牌和 Bearer 令牌)、API 密钥及 Oauth 进行登录访问。
REST API 的其他优势包括:
系统可扩展性 — REST API 可以高效扩展,因为 REST 优化了客户端和服务器之间的交互。RESTful 无状态约束条件可减轻服务器负载,因为服务器不必保存来自先前请求或有关先前请求的信息。 此外,可缓存性能够减少可能造成瓶颈的“客户端-服务器”交互的数量。这有助于构建可扩展的高性能 API。
开发灵活性 — 许多企业应用需要与内部或第三方 API 进行通信。RESTful Web 服务支持客户端和服务器之间分离开来,以便两者独立演进。
技术独立性 — REST API 独立于应用所用的编程语言和框架。客户端和服务器应用无需使用相同的语言或框架,这些语言或框架可在不影响 API 设计或通信流程的情况下进行更改。
REST 仍是用于连接客户端和服务器应用的最常见的架构,而 GraphQL(由 Facebook 于 2012 年开发,在 2015 年实现开源)则是 REST 的替代方案。GraphQL API 比 REST API 更高效,因为所需的所有数据都在单个请求中以标准化的形式进行请求,但 REST 仍在一些领域表现出色。GraphQL 的学习难度较大,而且可缓存性远不如 REST。此外,应用通常由资源驱动,无需使用 GraphQL 等查询语言。也就是说,每种模型都有其优缺点,企业可以兼而用之。
GraphQL 是一种开源 API 查询语言,能够在一次 API 调用中从多个来源获取数据。它还是一种服务器端运行时,用于对现有数据执行查询。GraphQL 强调为客户端仅仅提供所请求的数据,并且同时还提供完整的 API 数据描述,从而可以简化 API 的扩展和演变。
GraphQL 在设计时充分考虑了灵活性、速度和开发人员。借助 GraphQL,开发人员能够以他们认为合适的方式构建 API,然后利用 GraphQL 规范来确保 API 可供客户端使用。
GraphQL 查询的一个重要理念是返回的数据是可预测的。返回的正是所请求的内容,而不是多余的代码串。这种声明式数据获取在带宽有限的移动设备上特别有用。使用 GraphQL 的应用快速稳定,因为控制请求和接收的数据的是这些应用,而不是服务器。即使在网络连接速度较慢的情况下,它们的速度也很快,因为单个请求可同时返回多个请求的条目。
基于 GraphQL 将数据进行了简化,API 被按照类型和字段而非端点进行划分。这意味着能够在单个端点上访问所有数据,从而使得应用只需查询必要的内容。由于 GraphQL 可降低操作复杂性,它非常适合精简的 API 互联解决方案的工作流。
2012 年,Meta(当时的 Facebook)需要一个可支持其 Facebook 移动应用的强大的数据获取型 API。在 Lee Byron 的领导下,Facebook 开发了 GraphQL 以简化数据获取——特别是从产品设计师和开发人员的角度来看。GraphQL 首先在 Facebook 内部使用,后于 2015 年公开发布并开源。按照许多其他开源项目的发展轨迹,2019 年 GraphQL 项目被转移到由 Linux 基金会托管的 GraphQL 基金会。
GraphQL 被设计为REST 架构的替代方案。标准 REST API 需要通过单独的 HTTP GET 请求从多个 URL 加载信息。借助 GraphQL API,所有数据均可通过单个 POST 请求进行检索。虽然 REST 和 GraphQL 都返回 JSON 格式的响应,但 GraphQL 侧重于精简和整合数据。
GraphQL 支持细粒度的数据请求,并加强了客户端对所发送信息的控制。客户端以 POST 请求的形式发送 GraphQL 查询,然后服务器会返回 JSON 格式的响应。GraphQL 不需要特定的应用架构,可部署在多种环境(包括集成式开发环境 [IDE])中,并能够与现有 API 管理工具结合使用,或者在现有 REST API 之上使用。
GraphQL 中的一些关键术语包括:
模式(Schema)——由 API 开发人员创建,显示客户端可查询的数据;模式由对象(object)类型组成,对象类型定义了客户端可请求的信息以及代表对象特征的字段。
查询(Query)——查询经过验证后,根据模式予以执行。如果不定义对象类型,GraphQL 将无法执行查询。
解析器(Resolver)——附加到每个模式字段的解析器函数会在 API 执行中被调用以生成值。解析器是 GraphQL 的关键架构组件。
GraphQL 的独特之处在于返回的响应可以映射查询的结构(由模式定义)。这简化了客户端的解析工作,因为服务器响应的格式完全可预测。
GraphQL 的层次性决定了对象之间的关系,并使其在分层用户界面中非常好用。另外 GraphQL 也是强类型的,这意味着每个查询级别都与某个数据类型相匹配。然后,这些类型会定义一组字段。这一点与 SQL 类似——会在完成查询前显示描述性错误消息。
解析器是将 GraphQL 字段(field)、边缘(edge)、更新(mutation)、查询(query)及订阅(subscription)连接到数据源(和微服务)的关键架构模块。
GraphQL 查询的独特之处在于映射响应。由于您知道它将与来自 API 请求的格式相匹配,查询返回的数据就变得可预测了。当返回的数据格式遵循客户端查询的格式时,服务器端就被简化了。
GraphQL 的一大优势是,可通过扩展来提供 REST 中没有的特性。GraphQL 还具有以下优点。
GraphQL 模式会在 GraphQL 应用中设置单一信源,它提供了一个可以了解所有数据的地方。虽然一般会在服务器端定义 GraphQL 的模式,但客户端仍可根据模式来查询和写入数据。
在 REST 架构中,过度获取很快就会成为问题:应用(后端)定义每个资源可用的数据,并在其响应中返回所有数据,即使客户端(前端)需要的只是其中的一个数据元素。而 GraphQL 的调用是单程的,只为客户端提供所请求的数据,不会过度提供多余数据。
由于数据类型经过了明确定义,因此在 GraphQL 中,客户端和服务器之间的通信比在 REST 中更清晰。该底层结构还意味着不需要使用复杂的客户端来调用 GraphQL 服务器。如欲了解更多信息并查看运行代码,请参考 GraphQL 官方页面上有关客户端和服务器的介绍。
API Federation(API 联邦)提供了一套设计原则和工具,便于在定义好的上下文中将多个 service 作为一个具有一致性的 API 暴露给用户,同时也允许该上下文中的 service 不受限制地演变。GraphQL 支持在不中断先前查询的情况下,邦联整个 API 进行演变,从而实现扩展。这种可扩展性是许多企业争相采用 GraphQL 的原因之一。
GraphQL 的 introspective(自省)属性支持从 GraphQL API 中检索 GraphQL 模式。客户端还可以请求可用数据类型列表——这十分适合文档和测试的自动生成,以及在多个微服务中检索模式的情况。
虽然采用 GraphQL 的原因有很多,但它也有一些值得注意的缺点。举例来说,它并非完全开箱即用,需要使用特殊的库才能使用别人的 API。而且,总的来说,与 REST 相比,GraphQL 需要更多的工具支持。
与 REST 相比,GraphQL 具有以下缺点。
对于习惯使用 REST API 的开发人员来说,GraphQL 更难掌握。它还改变了工作流——使用 GraphQL 的 API 团队还必须编写可维护的 GraphQL 模式(schema)。不过,如果从头学起,GraphQL 也很容易学习和使用,因为请求和响应具有相同的结构。
GraphQL 可能需要新的 API 管理策略,而 REST API 通常适合现有的 API 管理模式。这是一个重要的考虑因素,因为新增 API 管理策略会增加总支出。
GraphQL 中的缓存机制不如在 REST 中简单。在 REST 中,请求通常使用 HTTP 方法(GET、POST、PUT 或 DELETE)。标准的 GraphQL 请求使用的是 POST 方法,其在 HTTP 层面不可缓存。
GraphQL 中的缓存变得复杂的原因还包括只有一个端点,因为这意味着该端点的 URL 会生成多个不同的不可缓存响应(这有利于获取数据,但不利于缓存)。即使所有的请求都使用同样的对象结构,服务器端的开发人员还是需要使用不同的查询语句。
不过,好在许多 GraphQL 库都提供可开箱即用的缓存机制。
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn
更多 NGINX 相关的技术干货、互动问答、系列课程、活动资源: 开源社区官网 | 微信公众号