NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

为什么你的下一个 API 应该是 GraphQL 而不是 REST

  • 2023-02-09
    北京
  • 本文字数:2692 字

    阅读完需:约 9 分钟

为什么你的下一个API应该是GraphQL而不是REST

REST 在几年前曾经风靡一时,但现在 GraphQL 拥有更好的工具和开发者体验。


几年前,我所有的 API 都是REST API。我知道 GraphQL 不可小觑,但也并没有花太多时间学习它。早期的探索表明,GraphQL并不是一颗神奇的 API 银弹。你仍然需要编写所有的逻辑,仍然需要使用奇怪的模式文件。既然如此,我们为什么要选择为额外的复杂性而烦恼呢?REST API 很简单,不需要额外的模式。每个资源都有简单的端点,大多数时候,与 API 端点相关的代码都是简单的 CRUD。


在过去的一年里,我们从 RPC API 切换到更好的 GraphQL。这对我们的应用程序来说是件好事,因为 RPC 接口只是 GraphQL 的一个糟糕实现,而且应用程序中有复杂的关系,因此使用 GraphQL 更为合适。


虽然我对此持怀疑态度,但也很想看看事情将会如何发展。事实证明,现在的工具非常棒,而且这样做的好处是巨大的。


一年后,我迷上了它。我的朋友开始了一个业余项目,当我想到需要再次与一堆 REST API 打交道时,我的心一沉。GraphQL 提供了更好的开发者体验。那么,为什么 GraphQL 如此神奇?

代码基本相同


在编写处理请求的代码时,处理逻辑的主要代码几乎是相同的。


例如,这是一些获取给定 ID 资源的伪代码。


func resolver(parent, args, context): Resource {  const id = args.id  const resource = db.Resource.FindOne({id: id})  return resource}
复制代码


通过 ID 获取资源(GraphQL)


这是 GraphQL 还是 REST 的端点?


代码几乎一模一样。主要的区别在于函数签名。获取、更新和删除资源集合也是如此。


二者都是将参数传递给函数并处理请求。有一些小的语法变化,但大部分逻辑保持不变。


不过 GraphQL 有一个值得注意的好处,就是可以获取资源间的关系。


假设你有一个包含两个资源的模式:一个 Author(作者),它有许多 Post(帖子)。你只能根据作者获得帖子,所以你的 REST API 看起来像这样。


/authors//authors/:author_id//authors/:author_id/posts/authors/:author_id/posts/:post_id
复制代码


你实现了四个不同的 API 来获取每个层级的数据。


但你可以使用 GraphQL 更简单地达到同样的目的。


type Query {  authors(id: Int): [Author!]!}
type Author { posts(id: Int): [Post!]!}
复制代码


还有其他方法也可以实现这一点,但这种模式可以让你:


  1. 不指定 ID 获取所有作者(这是可选的);

  2. 通过特定的 ID 获取作者;

  3. 获取所有作者的所有文章;

  4. 获取单个作者的所有文章;

  5. 只获取给定作者的给定文章。


就我个人而言,我的根查询经常将 author 和 authors 分开,避免为单个资源返回一个数组。将 Post 放在 Author 下,然后在 Author 的上下文中编写 Post 解析器。这个简单的嵌套让用户可以一起查询作者和他们的帖子。

支持工具已经发展得非常好


GraphQL 是一种强类型模式,可以为客户端和服务器库生成代码。


因此,客户端可以获取具有完美类型信息的数据。与手动编写的 REST API 相比,GraphQL 的类型安全是一个巨大的优势。有些工具可以为 REST API 生成类型,例如 Swagger/OpenAPI,但这些工具并没有内置到规范中,所以你不会自动获得这些功能。


GraphQL 在模式中内置了注释,还提供了一个自检 API,可以实现自文档化。有了编写良好的注释,就不需要单独维护文档。


类似的,因为模式是强类型的,所以实际上你都不需要构建自定义客户端库。服务通常会提供客户端库,这些库提供了易于使用的类型和方法。GraphQL 内置了这些,你只需要用它编写一个客户端。


你还可以获得为服务器解析器构建的类型。有些语言,比如 Go,会生成整个解析器函数。你需要做的是填充内容。其他的,比如 TypeScript,会生成所有的类型,你可以在解析器中使用它们来保证类型安全。

类型可以隐藏敏感信息


你在 GraphQL 模式中定义数据的类型,这为你提供了一种便利的方式来剔除敏感信息。例如,假设你有一个 User 类型,它映射到数据库中的一条用户记录,你可能在对象种保存了个人信息,如电子邮件地址或散列过的密码。


如果没有合适的工具,你可能会这么操作:


func handler(request, response) {  const user = db.User.findCurrent()  // 这样会把邮件地址和密码也返回!  return user}
复制代码


它会返回用户的所有字段。你需要把敏感信息剔除掉。


func handler(request, response) {  const user = db.User.findCurrent()  delete user.email  delete user.password  return user}
复制代码


GraphQL 通过特定的类型(在 Go 或 TypeScript 中)可以自动完成这个操作,只公开模式中定义的字段。你可以将对象返回给 GraphQL 解析器,并只公开模式中定义的字段。

用于快速验证查询的工具


测试 GraphQL 也变得更容易了,因为一些工具内置了强大的支持。我目前最喜欢的是 Insomnia,用于在应用程序之外测试 GraphQL 查询。Insomnia 会获取模式,并提供自动完成查询的功能,支持变量输入。此外,你还可以导出项目并将其包含在源代码中,方便人们进行快速的探索和使用它们。


还有其他一些很好的工具,比如 Apollo(https://www.apollographql.com/)。

不纯粹的 REST API


随着时间的推移,我注意到 REST 有一个缺点——并不是每个操作都能很好地映射成 CRUD。有一类操作可以被映射成这种格式,但可能没有意义。


  • 一次创建多条记录;

  • 一次更新多条记录;

  • 启动长时间运行的作业;

  • 取消作业。虽然我相信你可以写出有意义的 REST API(使用 POST /job 启动作业,它将返回 HTTP 202 而不是 200!),但也存在争议,例如,它究竟是取消作业还是删除作业,还是修改作业?


将批量更新作为一个资源,还是操作多个资源?


REST 没有针对这些操作提供有意义的语义定义,而 GraphQL 的 mutation 可以被任意命名,这样你就可以:


mutation cancelJob(id: Int!): Job
复制代码


不管是 PUT 还是 DELETE 操作,都是取消作业——这种灵活性带来了更有表现力的 API。

单个请求


在为页面请求数据时,REST API 只返回它们的资源。通常情况下,如果你想获取相关的资源,需要先获取 X,然后是 X 的 Y。


一些 REST API 允许你获取相关的资源,这很好。但你不能获取不相关的资源,如 X 和 Z,但 GraphQL 可以,你可以用多个根查询来获取它们。


在使用 GraphQL 时,你只需要发出一个 HTTP 请求就可以获取所有数据。


现在,如果你获取的数据太多,仍然可能发生灾难性的错误。但在大多数情况下,服务器可以有效地缓存数据并在单个请求中返回大量信息。

GraphQL > REST


GraphQL 是一种强大的查询语言,它在过去几年里不断发展。它提供了令人难以置信的工具,让你可以专注于业务逻辑。此外,你在定义 API 时具有很大的灵活性,让你拥有了更多的控制权。


REST 比之前的 API 要好很多,它提供了一条重新思考数据和以一种朴素的方式创建 API 的途径。


但 GraphQL 更强大,更容易使用,并且提供了更好的开发者体验。你的下一个 API 应该是 GraphQL,而不是 REST。


原文链接:

https://ethanmick.com/why-graphql-is-better-than-rest/

公众号推荐:

跳进 AI 的奇妙世界,一起探索未来工作的新风貌!想要深入了解 AI 如何成为产业创新的新引擎?好奇哪些城市正成为 AI 人才的新磁场?《中国生成式 AI 开发者洞察 2024》由 InfoQ 研究中心精心打造,为你深度解锁生成式 AI 领域的最新开发者动态。无论你是资深研发者,还是对生成式 AI 充满好奇的新手,这份报告都是你不可错过的知识宝典。欢迎大家扫码关注「AI前线」公众号,回复「开发者洞察」领取。

2023-02-09 10:265084

评论 1 条评论

发布
用户头像
graphql这种通用接口的方式褒贬不一
2023-02-13 09:24 · 广东
回复
没有更多了
发现更多内容

阿里云 Landing Zone 上好云伙伴联盟正式起航

云布道师

阿里云 2022云栖大会

袋鼠云产品功能更新报告 02 期丨有亿点点走心!

袋鼠云数栈

重磅发布!星汉未来全国开发者悬赏计划

星汉未来

云计算 开发者 运维 云原生 星汉未来

Eureka框架的原理

阿泽🧸

Eureka 11月月更

Knative架构解析

穿过生命散发芬芳

Knative 11月月更

【线上分享会回顾】九科信息董事&产品VP傅恺分享流程挖掘实践案例

九科Ninetech

无线标准802.11ac 和 802.11ax到底有什么区别?哪个更快?

wljslmz

网络技术 无线技术 802.11ac 802.11AX 11月月更

Redis的一些概念

饱饱巴士

redis 11月月更 redis梳理

2022-11微软漏洞通告

火绒安全

安全漏洞

三分钟带你了解一站式大数据平台运维管家 ChengYing 产品包制作

袋鼠云数栈

开源密码管理器更安全吗?(2)

神锁离线版

开源 网络安全 信息安全 数据安全 密码管理器

Oracle 表空间创建标准(二)

默默的成长

oracle 前端 11月月更

五大模型揭秘深度学习用于时序预测的最新进展

云智慧AIOps社区

人工智能 机器学习 深度学习 算法 模型

费劲拿到的阿里P8架构师私藏(java岗的)JCF和JUC源码分析与实现笔记

程序知音

Java 高并发 源码刨析 java架构 后端技术

金融服务的超级App

FN0

生态 超级app 组装式应用

大数据生态中的 RocketMQ 5.0

阿里巴巴云原生

阿里云 RocketMQ 云原生

得物极光蓝纸箱尺寸设计实践

得物技术

算法 遗传算法 供应链 建模 运筹

七层模型

初学者

网络 服务器 11月月更

双11niubility的数据恢复软件,获得更专业的数据恢复服务

淋雨

数据恢复 文件恢复

报名|企业数字化转型有何“利器”?一起来揭秘

元年技术洞察

数字化转型

获奖作品《重力》超详细制作过程!建议码住!

Renderbus瑞云渲染农场

Blender制作教程

阿里这份Java程序性能优化指南,让你的程序快上200%

小小怪下士

Java 程序员 性能优化

内存数据库如何发挥内存优势?

C++后台开发

算法 内存数据库 后端开发 linux开发 C++开发

云原生系列五:Kafka 集群数据迁移基于Kubernetes的内部

叶秋学长

kafka\ kurbernetes 11月月更

SQL编写规范

默默的成长

前端 sql 11月月更

持续优化,欣欣向云 | RocketMQ Operator 0.3.0 正式发布

阿里巴巴云原生

阿里云 RocketMQ 云原生

【C语言】do 关键字

謓泽

11月月更

颠覆传统BOM检查!用这个方法既​简单、快速又准确

华秋PCB

工具 PCB BOM PCB设计

AI生命周期 | 聊聊数据准备阶段的偏见问题

澳鹏Appen

人工智能 机器学习 数据标注 数据训练 数据偏见

实战指南 | Serverless 架构下的应用开发

阿里巴巴云原生

阿里云 Serverless 云原生

KeeWiDB的高性能修炼之路:架构篇

腾讯云数据库

数据库 nosql redis 腾讯云数据库 KeeWiDB

为什么你的下一个API应该是GraphQL而不是REST_语言 & 开发_Ethan Mick_InfoQ精选文章