写点什么

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

2023-02-09 10:265232

评论 1 条评论

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

2022备战秋招10W字面试小抄pdf版,附操作系统、计算机网络面试题

程序员啊叶

Java 编程 程序员 架构 java面试

美团二面:为什么Redis会有哨兵?

王小凡

Java redis 编程 程序员 开发

2022年金三银四Java面试宝典,横扫春招+社招+秋招

程序员啊叶

Java 编程 程序员 架构 java面试

搞定RocketMQ这二十三点,大厂面试稳了

王小凡

Java 数据库 程序员 面试 大厂面试

如何对话CIO/CTO

凌云Cloud

销售 企业管理系统 CIO To B业务

Redis网红高频面试题三连:缓存穿透?缓存击穿?缓存雪崩?

程序员啊叶

Java 编程 程序员 架构 java面试

兆骑科创海内外引进高层次人才,创新创业项目对接

兆骑科创凤阁

收藏!0 基础开源数据可视化平台 FlyFish 大屏开发指南

云智慧AIOps社区

大前端 低代码 开源项目 数据可视化工具 开源推荐

GIS数据漫谈(五)— 地理坐标系统

ThingJS数字孪生引擎

细数国产接口协作平台的六把武器!

Liam

开发 Postman API 接口开发 前后端协作

从存储角度看自动驾驶必经之路

焱融科技

人工智能 自动驾驶 存储 文件存储 分布式文件存储

4 轮拿下字节 Offer,面试题复盘

程序员啊叶

Java 编程 程序员 架构 java面试

C语言怎么学?这篇文章给你完整答案

图灵教育

C语言

x-sheet 开发教程:初始化配置自定义布局

OpenHacker

Excel x-sheet sheet spreadsheet

怎么会不喜欢呢,CI/CD中轻松发送邮件

Jianmu

持续集成 低代码 邮件 通知

字节跳动Java研发面试99题(含答案):JVM+Spring+MySQL+线程池+锁

程序知音

Java 字节 程序员面试 后端技术 八股文

人工智能发展到什么阶段了,产生“自主情感”可能吗?

燕陈华

人工智能 深度学习 卷积神经网络

施耐德电气、欧莱雅等企业巨头如何开放式创新?DEMO WORLD世界创新峰会揭秘

创业邦

低代码实现探索(四十五)业务参数

零道云-混合式低代码平台

选择体育场馆的LED显示屏时应该注重哪些方面

Dylan

LED显示屏 户外LED显示屏 led显示屏厂家

面试好难啊!蚂蚁金服的六轮面试我是强撑过来!差点OUT(面试复盘)

程序知音

Java 阿里 程序员面试 BAT面试题 八股文

技术分享| 快对讲综合调度系统

anyRTC开发者

音视频 指挥调度 快对讲 语音对讲 视频对讲

1000个字带你一次性搞懂JavaAgent技术,反正我是彻底服了

程序员啊叶

Java 编程 程序员 架构 java面试

【微信小程序】项目实战—抽签应用

flow

签约计划第三季

美团到餐“祖传数仓”标准化治理笔记

老猎人

Spring Cloud 架构

Damon

7月月更

图的遍历的定义以及深度优先搜索和广度优先搜索(二)

乔乔

7月月更

技术实践干货 | 初探大规模 GBDT 训练

观远数据

人工智能 机器学习

带来高价值用户体验的低代码开发平台

力软低代码开发平台

浅谈AI深度学习的模型训练和推理

GVision

建木持续集成平台v2.5.2发布

Jianmu

持续集成 低代码 CI/CD gitops

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