了解API相关范式(RPC、REST、GraphQL)

简介: 了解API相关范式(RPC、REST、GraphQL)前言两个独立的应用程序经常需要相互访问交谈,或则可以是同一个应用程序,但部署在不同的服务器,或者现在常用的前后端分离式架构等等需要经常相互访问交谈,因此开发人员经常搭建桥梁API(Application Programming Interfaces)关于API的定义,你可以简单看看这篇文章-- What is an API: Definition, Types, Specifications, Documentation

了解API相关范式(RPC、REST、GraphQL)

前言

两个独立的应用程序经常需要相互访问交谈,或则可以是同一个应用程序,但部署在不同的服务器,或者现在常用的前后端分离式架构等等需要经常相互访问交谈,因此开发人员经常搭建桥梁API(Application Programming Interfaces)

关于API的定义,你可以简单看看这篇文章-- What is an API: Definition, Types, Specifications, Documentation

关于历史出现的API范式,我们可以参考 Rob Crowley的这张图:

目前使用的较多的就是RPC、REST、GraphQL,接下来将会对这三种范式进行优缺点的讨论...

RPC(Remote Procedure Call)

简介

RPC 出现的最初目的,就是为了让计算机能够跟调用本地方法一样去调用远程方法,我们可以简单理解为一个本地方法调用+网络通信

工作过程

客户端调用远程过程,将参数和附加信息序列化为消息,并将消息发送到服务器。收到消息后,服务器反序列化其内容,执行请求的操作,并将结果发送回客户端。

相关规范

RPC只是一个概念,但是这个概念有很多规范,都有具体的实现,如:RMI(Sun/Oracle)、Thrift(Facebook/Apache)、Dubbo(阿里巴巴/Apache)、gRPC(Google)、Motan1/2(新浪)、Finagle(Twitter)、brpc(百度/Apache)、.NET Remoting(微软)、Arvo(Hadoop)、JSON-RPC 2.0(公开规范,JSON-RPC 工作组)

参考《凤凰架构》

  • 朝着面向对象发展,不满足于 RPC 将面向过程的编码方式带到分布式,希望在分布式系统中也能够进行跨进程的面向对象编程,代表为 RMI、.NET Remoting,之前的 CORBA 和 DCOM 也可以归入这类,这条线有一个别名叫做分布式对象(Distributed Object)。
  • 朝着性能发展,代表为 gRPC 和 Thrift。决定 RPC 性能的主要就两个因素:序列化效率和信息密度。序列化效率很好理解,序列化输出结果的容量越小,速度越快,效率自然越高;信息密度则取决于协议中有效荷载(Payload)所占总传输数据的比例大小,使用传输协议的层次越高,信息密度就越低,SOAP 使用 XML 拙劣的性能表现就是前车之鉴。gRPC 和 Thrift 都有自己优秀的专有序列化器,而传输协议方面,gRPC 是基于 HTTP/2 的,支持多路复用和 Header 压缩,Thrift 则直接基于传输层的 TCP 协议来实现,省去了额外应用层协议的开销。
  • 朝着简化发展,代表为 JSON-RPC,说要选功能最强、速度最快的 RPC 可能会很有争议,但选功能弱的、速度慢的,JSON-RPC 肯定会候选人中之一。牺牲了功能和效率,换来的是协议的简单轻便,接口与格式都更为通用,尤其适合用于 Web 浏览器这类一般不会有额外协议支持、额外客户端支持的应用场合。

优点

实现 RPC 的可以传输协议可以直接建立在 TCP 之上,也可以建立在 HTTP 协议之上。大部分 RPC 框架都是使用的 TCP 连接(gRPC使用了HTTP2)。

  • 调用简单,清晰,透明,不用像 rest 一样复杂,就像调用本地方法一样简单(同样也是缺点,就是后续提到的耦合度强)
  • 高效低延迟,性能高
  • 使用自定义 TCP 协议进行传输可以极大地减轻了传输数据的开销。 这也就是为什么通常会采用自定义 TCP 协议的 RPC 来进行进行服务调用的真正原因。
  • 成熟的 RPC 框架还提供好了“服务自动注册与发现”、"智能负载均衡"、“可视化的服务治理和运维”、“运行期流量调度”等等功能减轻开发者心智负担

缺点

  • 与底层系统紧密耦合:API 的抽象级别有助于其可重用性。它对底层系统越紧密,对其他系统的可重用性就越低。RPC 与底层系统的紧密耦合不允许在系统功能和外部 API 之间存在抽象层。这会引发安全问题,因为很容易将有关底层系统的实现细节泄露到 API 中。RPC 的紧耦合使得可扩展性需求和松耦合团队难以实现。因此,客户端要么担心调用特定端点的任何可能的副作用,要么尝试找出要调用的端点,因为它不了解服务器如何命名其功能。
  • 各个函数可能复用率低:创建新功能非常容易(这也可以算作优点之一)。因此,可能经常没有编辑现有的,而是创建了新的,最终得到了大量难以理解的重叠功能。

REST(Representational state transfer)


介绍

REST – REpresentational State Transfer

RESTful实例可以查看我之前写的Django这个笔记或者NestJS这个笔记,如果你使用过REST,可以直接忽略这段话,继续下面的阅读。

下面谈谈偏理论的东西,如何理解REST:

REST本质上是面向资源编程,这也是与RPC面向过程编程最主要的区别,需要注意的是,REST只是一种风格,不遵循它编译器也不会报错,只是不能享受到对应的一些好处罢了,需要设计者灵活考虑。

既然是面向资源编程,所以我们可以这样理解一个符合RESTful的接口:

  • 看URL就知道我们的目标是什么资源
  • 看方法就知道我们需要对该资源进行什么样的操作
  • 看返回码就知道操作的结果如何

比如我们要获取这个编号的咖啡信息

curl -X GET https://api.justin3go.com/coffees/1


REST的指导原则


REST的指导原则部分内容引用该篇文档的机翻:

  • 统一接口通过将 通用性原则应用于 组件接口,我们可以简化整体系统架构并提高交互的可见性。多个体系结构约束有助于获得统一的接口并指导组件的行为。以下四个约束可以实现统一的REST接口:
  • 资源标识 ——接口必须唯一标识客户端和服务器之间交互中涉及的每个资源。
  • 通过表示操作资源 ——资源在服务器响应中应该有统一的表示。API 消费者应该使用这些表示来修改服务器中的资源状态。
  • 自描述消息 ——每个资源表示都应该携带足够的信息来描述如何处理消息。它还应提供有关客户端可以对资源执行的其他操作的信息。
  • 超媒体作为应用程序状态的引擎 ——客户端应该只有应用程序的初始 URI。客户端应用程序应使用超链接动态驱动所有其他资源和交互。
  • 客户端服务器
    客户端-服务器设计模式强制 关注点分离,这有助于客户端和服务器组件独立发展。
    通过将用户界面问题(客户端)与数据存储问题(服务器)分开,我们提高了跨多个平台的用户界面的可移植性,并通过简化服务器组件提高了可扩展性。
    随着客户端和服务器的发展,我们必须确保客户端和服务器之间的接口/契约不会中断。
  • 无状态
    无状态 要求从客户端到服务器的每个请求都必须包含理解和完成请求所需的所有信息。
    服务器无法利用服务器上任何先前存储的上下文信息。
    为此,客户端应用程序必须完全保持会话状态。
  • 可缓存
    缓存约束 要求响应应隐式或显式将自身标记为可缓存或不可缓存。
    如果响应是可缓存的,则客户端应用程序有权在以后的等效请求和指定时间段内重用响应数据。
    分层系统
    分层系统风格允许架构通过约束组件行为由分层层组成。
    例如,在分层系统中,每个组件都无法看到与其交互的直接层之外的信息。
  • 按需代码(可选
    REST 还允许通过下载和执行小程序或脚本形式的代码来扩展客户端功能。
    下载的代码通过减少需要预先实现的功能数量来简化客户端。服务端可以将部分特性以代码的形式交付给客户端,客户端只需要执行代码即可。

优点

  • 解耦客户端和服务器:耦合性低,兼容性好,提高开发效率
  • 不用关心接口实现细节,相对更规范,更标准,更通用,跨语言支持
  • 缓存友好:重用大量 HTTP 工具,REST 是唯一允许在 HTTP 级别缓存数据的样式。相比之下,任何其他 API 上的缓存实现都需要配置额外的缓存模块。
  • 多种格式支持:支持多种格式来存储和交换数据

缺点

  • 没有统一的REST结构:正如之前所说,只是一种风格,有一些指导原则,所以构建REST API没有完全正确的方法。如何建模资源以及建模哪些资源仍灵活多变,取决于业务场景。这使得REST理论上很简单但实践中较为困难
  • 高负载:REST API会返回大量丰富的元数据,方便客户端仅从响应中就可以了解有关应用程序状态的所有必要信息,随之而来的就是一定的性能问题(高负载)。这个缺点和下面一个缺点也是后续GraphQL被提出的主要原因。
  • 过度获取和获取不足:无法预估后续业务场景会如何变化,这导致了最初设计的API很难根据业务场景不断变化并且不能影响到之前的业务。

GraphQL(Graph query language)


介绍

如果你熟悉REST,但不熟悉GraphQL,推荐阅读这篇文章--GraphQL vs. REST,里面有较为详细的对比与介绍

首先来说,它是一种查询语言,具有一定的语法规则(即学习成本--有编程基础的话较小),可以解决上述REST中的一些问题。

引用官网的介绍:

GraphQL 是一种用于 API 的查询语言,也是使用现有数据完成这些查询的运行时。GraphQL 为您的 API 中的数据提供了完整且易于理解的描述,使客户能够准确地询问他们需要什么,仅此而已,随着时间的推移更容易发展 API,并启用强大的开发人员工具。

Q&A

这里引用一下官网的FAQ

ls GraphQL a database language like SQL?

No, but this is a common misconception.

GraphQL is a specification typically used for remote client-server communications. Unlike SQL, GraphQL is agnostic to the data source(s) used to retrieve data and persist changes. Accessing and manipulating data is performed with arbitrary functions called resolvers. GraphQL coordinates and aggregates the data from these resolver functions, then returns the result to the client. Generally, these resolver functions should delegate to a business logic layer responsible for communicating with the various underlying data sources. These data sources could be remote APIs, databases, local cache, and nearly anything else your programming language can access.

For more information on how to get GraphQL to interact with your database, check out our documentation on resolvers.

Does GraphQL replace REST?

No, not necessarily. They both handle APIs and can serve similar purposes from a business perspective. GraphQL is often considered an alternative to REST, but it’s not a definitive replacement.

GraphQL and REST can actually co-exist in your stack. For example, you can abstract REST APIs behind a GraphQL server. This can be done by masking your REST endpoint into a GraphQL endpoint using root resolvers.

For an opinionated perspective on how GraphQL compares to REST, check out How To GraphQL.

看到上述两个FAQ我自己蹦出了这样的想法:

首先我想到的是一个比较荒谬的问题:既然GraphQL是一种查询语言,SQL也是一种查询语言,那为什么不直接前端传入sql直接拿数据呢?

显然这是有很多问题的,最主要的问题就是这相当于无后端,全部逻辑都集中在了客户端,这对于客户端的压力是非常大的,并且也是非常不安全的,就类似于破解单机游戏一样...

高耦合的话我理解前端程序也可以进行多层抽象来解耦,比如MVC这类。但这又要重新经历一次类似的web架构演变,对现有的生态也是极大的破坏...

上述只是一些胡乱猜想,不必当真,回到这里的话GraphQL就是对后端提供的GraphQL运行时查询的语言,官方语法为SDL。而这个运行时是应用程序业务逻辑外面的一层接口暴露,我们开发人员需要对每一个接口业务字段

然后与REST的区别我理解就是:二者本质都可以理解为面向资源编程

  • GraphQL通过一个运行时,使用规定的语法可以更加精准灵活地操作资源(灵活度也是有一定限度的,只是相对来说)
  • 而REST就能根据提前定义好地URL,通过不同的方法操作资源

这部分可能各有各的想法思考,欢迎友善讨论~

工作过程

在查询之前需要schema,客户端可以验证他们的查询以确保服务器能够响应它。在到达后端应用程序时,GraphQL 操作将针对整个schema进行解释,并使用前端应用程序的数据进行解析。向服务器发送大量查询后,API 会返回一个 JSON 响应,其中的数据形状与我们请求的数据完全相同。

参考:_Jonas Helfer

除了 RESTful CRUD 操作之外,GraphQL 还具有允许来自服务器的实时通知的订阅

GraphQL需要我们对暴露出去的每一个字段规定一个函数进行处理,比如一个简单的node搭建的应用程序如下:

var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graph');
// 构建schema,这里定义查询的语句和类型
var schema = buildSchema(`
  typr Account {
    name: String
    age: Int
    sex: String
    department: String
  }
  type Query {
    hello: String
    accountName: String
    age: Int
    account: Account
  }
`)
// 定义查所对应的resolver,也就是查询对应的处理器
var root = {
  hello: () => 'Hello world',
  accountName: () => 'justin3go',
  age: () => 18,
  account: () => ({
    name: '',
    age: 18,
    sex: '',
    department: ''
  })
}
var app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql:true
}));
app.listen(4000)


优点

  • 非常适合图形数据:深入链接关系但不适合平面数据的数据
  • 请求的数据不多不少,按需请求,非常灵活
  • 获取多个资源,只用一个请求
  • 描述所有可能类型的系统。便于维护,根据需求平滑演进,添加或者隐藏字段(无需版本控制)

缺点

  • 性能问题:GraphQL 以复杂性换取其强大功能。一个请求中包含太多嵌套字段会导致系统过载。因此,REST 仍然是复杂查询的更好选择。
  • 缓存复杂性:由于 GraphQL 没有重用 HTTP 缓存语义,因此它需要自定义缓存工作。
  • 一定的学习成本:没有足够的时间弄清楚 GraphQL生态和 SDL,许多项目决定遵循众所周知的 REST 路径。

总结



image.png

  • RPC 适用于内部微服务,IO 密集的服务调用用 RPC,服务调用过于密集与复杂,RPC 就比较适用
  • REST 具有 API 的最高抽象和最佳建模。但它在网络上往往更重、更固定(通常为了兼容会有冗余字段)
  • GraphQL在灵活获取数据上优势很大,但具有一定的学习成本。

最后


具体的API范式体会起来可能也是因人而异,上述的总结也可能有所偏差,欢迎友善讨论提出一些建议或者纠正一些错误


目录
相关文章
|
1月前
|
网络协议 JavaScript 安全
第十一篇 前沿趋势与展望:深入探索GraphQL、RESTful API、WebSocket、SSE及QUIC与HTTP/3
第十一篇 前沿趋势与展望:深入探索GraphQL、RESTful API、WebSocket、SSE及QUIC与HTTP/3
|
1月前
|
缓存 前端开发 API
构建可扩展的API:REST vs GraphQL
【5月更文挑战第14天】在API设计中,REST和GraphQL是两种主要的架构风格。REST基于HTTP协议,强调资源的无状态性和客户端-服务器模型,适合简单CRUD操作。而GraphQL提供更灵活的数据查询,允许客户端精确指定需求,减少HTTP请求和数据冗余,适合复杂场景和高性能需求。选择时要考虑项目需求、技术栈、性能和团队经验。
|
12天前
|
安全 Java API
Java一分钟之-GraphQL:查询语言与API设计
【6月更文挑战第11天】GraphQL,一种革命性的查询语言,正在改变Web开发中的API构建和使用方式。它允许客户端按需请求数据,减少冗余,提升性能。本文概述了GraphQL的核心理念,如声明式查询、强类型和统一入口,并讨论了Java开发者常遇问题:过度查询、Schema设计和安全性。解决方案包括使用Dataloader、优化Schema和实现授权机制。通过理解原理、关注性能、重视安全和持续实践,开发者能更好地利用GraphQL构建高效API。
23 2
|
1月前
|
JSON Java 网络架构
RPC与REST对比指南
【5月更文挑战第19天】使用RPC可以得到很轻的载荷、传输较轻、速度快、协议层少、转换快,但是会产生依赖性,做不到平台无关性,在安全性上较差。使用REST风格,则具备平台无关性、高安全性和独立性。
|
1月前
|
Prometheus 监控 Cloud Native
第七十一章 使用 REST API 监控 IRIS - 活动量指标
第七十一章 使用 REST API 监控 IRIS - 活动量指标
23 0
|
1月前
|
监控 API 网络架构
第七十章 使用 REST API 监控 IRIS - 互操作性指标
第七十章 使用 REST API 监控 IRIS - 互操作性指标
22 0
|
1月前
|
SQL 监控 API
第六十九章 使用 REST API 监控 IRIS
第六十九章 使用 REST API 监控 IRIS
22 0
|
1月前
|
缓存 前端开发 JavaScript
【专栏】GraphQL,Facebook 开发的API查询语言,正在前端开发中崭露头角
【4月更文挑战第27天】GraphQL,Facebook 开发的API查询语言,正在前端开发中崭露头角。它提供强类型系统、灵活查询和实时更新,改善数据获取效率和开发体验。掌握GraphQL涉及学习基础概念、搭建开发环境和实践应用。结合前端框架,利用缓存和批量请求优化性能,与后端协作设计高效API。尽管有挑战,但GraphQL为前端开发开辟新道路,引领未来趋势。一起探索GraphQL,解锁前端无限可能!
|
1月前
|
分布式计算 DataWorks 关系型数据库
DataWorks操作报错合集之在DataWorks同步数据时,遇到乱码问题,该怎么解决(rest api数据源)
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
34 0
|
1月前
|
JSON 安全 API
【专栏】四种REST API身份验证方法:基本认证、OAuth、JSON Web Token(JWT)和API密钥
【4月更文挑战第28天】本文探讨了四种REST API身份验证方法:基本认证、OAuth、JSON Web Token(JWT)和API密钥。基本认证简单但不安全;OAuth适用于授权第三方应用;JWT提供安全的身份验证信息传递;API密钥适合内部使用。选择方法时需平衡安全性、用户体验和开发复杂性。