【ArchSummit】如何通过AIOps推动可量化的业务价值增长和效率提升?>>> 了解详情
写点什么

为什么你的下一个 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:265086

评论 1 条评论

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

CDN是什么?

德胜网络-阳

金融科技的未来

CECBC

金融

DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座

华章IT

数据库 postgresql

重磅解读:K8s Cluster Autoscaler模块及对应华为云插件Deep Dive

华为云开发者联盟

容器 k8s 服务

每周一看:16份文档资料,程序员软硬实力全概览,总有一个适合你

小Q

Java 学习 程序员 架构 面试

帮助企业摆脱困境,名企归乡工程师:能成功全靠有它!

Philips

敏捷开发

爆料!前华为微服务专家纯手打500页落地架构实战笔记,已开源

996小迁

架构 面试 分布式 微服务 程序人生

架构师训练营 - 第 7 周课后作业(1 期)

Pudding

解决大中型浏览器(Chrome)插件开发痛点:自定义热更新方案——2.基于双缓存更新功能模块

梁龙先森

Java chrome 大前端 浏览器 技术方案

【云小课】版本管理发展史之Git+——代码托管

华为云开发者联盟

git 代码管理 托管

揭秘在召唤师峡谷中移动路径选择逻辑?

华为云开发者联盟

算法 地图 最短路径

Apache DolphinScheduler 是如何走进Apache的

代立冬

大数据 数据湖调度 DolphinScheduler Apache DolphinScheduler

浅谈API网关(API Gateway)如何承载API经济生态链

华为云开发者联盟

API 网关

架构训练营 - 第7周课后作业 - 学习总结

Pudding

百亿级数据分表后怎么分页查询?

艾小仙

Java MySQL 数据库 编程语言 分库分表

【涂鸦物联网足迹】涂鸦云平台接口说明

IoT云工坊

人工智能 物联网 API sdk 云平台

谈谈敏捷开发概念和迭代开发方案

Learun

敏捷开发

数字货币OTC交易所开发,交易所搭建方案

13530558032

《Python:Python编程简介:计算机编程和机器学习入门指南》

计算机与AI

Python

终于啃完了Java核心原理+框架“面试圣经”成功五面上岸美团

小Q

Java 学习 编程 架构 面试

终于啃完了这份Java核心原理+框架“面试圣经”,成功五面上岸美团

Java架构追梦

Java 架构 面试 微服务 框架开发

【运维思考】如何做好云上运维服务?

嘉为蓝鲸

云计算 运维 数字化转型 数据中心 云服务

LeetCode题解:77. 组合,递归回溯,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

架构师训练营第一期 - week8

习习

又一道比较运算符相关的面试题让我明白基础很重要

Gopher指北

Go 语言

架构师训练营第 1 期第 7 周总结

owl

极客大学架构师训练营

价值超10亿美元的直播系统架构图是什么样子的?

冰河

系统架构 高并发 高性能 亿级流量 直播架构

魏际刚:精准谋划我国供应链发展新方位

CECBC

供应链 物流

医疗界“最强大脑”落户杭州!阿里巴巴联合浙大一院共同打造

互联网

如何实现后台管理系统的权限路由和权限菜单

徐小夕

Java 大前端 编辑器 H5 数据可视化

如何稳扎稳打推进数字货币进程

CECBC

数字货币

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