GraphQL 深度探索
本博客是 GraphQL 系列文章的一部分,我们将逐一深入探讨 GraphQL 及其生态系统
GraphQL 规范于 2015 年由 Facebook 开源,其中包含一些基本实现,以及关于如何构建、使用、传输和处理数据和数据图的完全独特的方法。
如今,GraphQL 规范及其实现已由 Facebook 捐赠给 GraphQL 基金会,并以开放许可的形式由社区进行开发和治理,目前为止进展顺利。
如今,GraphQL 基金会的成员不仅包括 Facebook 这样的公司,还包括其他组织成员。
那一刻,许多人被它的威力、实用性和前景所折服,其余的都成为了历史。
如今,GraphQL 基金会致力于确保 GraphQL 和生态系统能够长期蓬勃发展,大量的项目、大量的工具(例如这个和这个
)只是生态系统发展壮大的几个例子,其中有大量语言、框架和工具将其作为一等公民来支持,甚至一些大型企业也将其作为其堆栈的一部分。
GraphQL 是Timecampus的核心,也是我们一切工作的核心。我们希望分享我们对 GraphQL 及其生态系统的热爱,以及一路走来汲取的宝贵经验。不仅仅是 GraphQL,我们还将深入研究各种开源工具、库、框架、软件和实践。
我确信我们接下来会有很多话题要聊。所以,为什么不先从常见问题解答开始呢?这正是我们今天要做的事情。我整理了一系列问题,并在下方进行了解答。
如果您是 GraphQL 新手,我建议您在阅读本博文之前先阅读以下链接:
GraphQL 简介 - 了解 GraphQL、它的工作原理以及如何使用它
如何使用 GraphQL - GraphQL 全栈教程免费开源教程,全面学习 GraphQL,从零开始,走向生产环境
探索 GraphQL - 这是你的 GraphQL 学习指南。学习模式和查询的基础知识,然后实现一些应用程序
GraphQL 教程 - GraphQL 正在成为现代 Web 和移动应用中使用 API 的新方式。然而,学习新事物总是需要
GraphQL 概念可视化 - GraphQL 通常被解释为“访问不同来源数据的统一接口”
如果你有兴趣深入了解 GraphQL 规范,可以在这里找到
因此,假设您已经了解 GraphQL 的基础知识,让我们直接开始吧。
为什么要从 REST 迁移到 GraphQL?它有什么好处?
首先我想说的是,GraphQL 不会取代 REST 或任何其他通信渠道。一切都取决于你的用例。对于小型项目来说,REST 的简单性可能比 GraphQL 的优势更重要,但随着团队规模的扩大、产品不断发展、生命周期的复杂化以及数据架构的日益庞大,你才会真正意识到 GraphQL 的价值。
来源:howtographql
在 REST 中,我们尝试为不同的数据路径构建不同的端点集。如果你查看REST 规范,你会发现它没有提供仅选择所需数据的方法,从而导致过度获取/获取不足;它不提供类型检查,也没有办法进行自省(除非你自己构建基于 OpenAPI 的文档);而且由于你最终必须从客户端调用不同的端点来获取应用程序所需的不同数据集,这很快就会变得繁琐。GraphQL 通过以下方式解决了所有这些问题:
来源:howtographql
这就是它的美妙之处。它拥有强大的类型系统,你可以选择所需的内容,避免过度获取/获取不足,你只需与单个端点通信,规范明确定义了查询的执行(串行或并行解析器),它与协议无关,不像 REST 那样依赖HTTP来完成所有操作,你甚至可以通过 http、GRPC、Websockets 等各种协议传输你的 GQL 查询——随便你怎么说。
HTTP、GRPC、GraphQL 和其他协议之间有什么区别?
总而言之,它们都是不同的。HTTP 本身是一种协议,并没有定义通过 HTTP 本身传输的数据的结构(最新版本是 http 3),GRPC使用协议缓冲区以 http 2 作为协议发送数据包(将来也可以扩展为使用 http 3),并且经常用于服务间通信,而 GraphQL 与传输层完全无关。它只是一种用于构造和在不同位置之间传输数据的规范,只要您有在服务器端解压缩或解密它们的逻辑,即使您对查询和变异进行压缩、加密或执行任何操作也无关紧要。因此,总而言之,它们服务于不同的用途。
如何像在 REST 中一样对我的 GraphQL 端点进行版本控制?
虽然你可以使用类似 GraphQL 端点的不同版本/v1/graphql
/v2/graphql
,但 GraphQL 建议你使用一个持续更新的数据图版本。这样,你可以弃用不再使用的字段,并在以后删除它们,并在需要时添加新字段,而不会影响架构的其余部分,从而避免可能发生的任何冲突。
定义我的模式的推荐方法是什么?
随着时间的推移,人们在 GraphQL 之上开发了许多抽象,突然间似乎有很多方法可以定义模式。
一些方法包括
- 将 SDL 直接写入
.gql
或.graphql
文件,然后加载并解析它们 - 使用Typegraphql之类的库将模式编写为代码
- 按照此处的定义直接将它们定义为 JS/TS 对象
并且随着时间的推移,还会有越来越多的东西可以进化。
需要理解的是,如果您使用的是 Node.js,graphql-js通常是所有库的底层实现,最终所有内容都会转换为 JS/TS 对象(通常是AST) ,最终使所有这些都成为现有模式定义方式之上的抽象。请注意,在其他语言中,甚至在 Node.js 中,如果您使用其他实现方式(例如graphql-jit),其实现可能会略有不同。
有哪些可用的 GraphQL 服务器以及它们有何不同?
如果您使用的是 Node.js,那么有很多 GraphQL 服务器的实现,例如express-graphql、apollo-server、mercurius、graphql-helix等等。如果您使用的是其他语言,可以在这里查看一个很棒的列表。
现在,结合 Node.js 的上下文来讨论,一切都取决于您的用例。
- 您是否依赖Apollo或其生态系统(例如联邦)?选择 apollo-server
- 你使用Express作为框架吗?使用 express-graphql
- 您正在使用 Fastify 吗?或者正在寻找一个性能强大、支持全面的 graphql 库?那就选择 Mercurius 吧!
- 您是否希望尽可能地实现模块化,减少代码臃肿,并逐步扩展功能?那就选择 graphql-helix 吧。
嗯,还有很多事情我没有提到,但这只是一个开始,它表明了一些需要考虑的因素。
事实上,如果你想了解每个 graphql-server 的性能,我建议你看看这个
利用 Typescript 发挥 GraphQL 作用的最佳方法是什么?
考虑到 GraphQL 和 Typescript 都是强类型的,我们实际上可以将它们结合起来,借助一些工具来获得更出色的体验。这将帮助我们将端到端的请求-响应生命周期变为强类型。
例如, The Guild有一些很棒的项目,比如GraphQL Codegen,我们可以使用它根据本地/远程模式生成类型,并且具有很好的 Typescript 集成,而且您还可以使用许多插件/接收器。
想要基于 GQL 文档生成 Typescript 对象?您可以尝试Typed Document Node。
或者你想直接用 Typescript 编写 schema 并维护严格的类型?试试Typegraphql
嗯,还有更多类似的例子,这只是一个开始。
如何设置我的开发环境来运行 GraphQL?
虽然这需要一篇单独的博客文章,但这里有一些例子。
- 如果您正在使用VSCode并希望启用语法高亮、验证、自动完成、代码完成等功能,您可以尝试使用VSCode GraphQL或Apollo GraphQL,具体取决于哪个更适合您。
- 如果您正在使用Typescript,最好将代码生成设置作为工作流程的一部分。
- 如果您希望在推送到版本控制时验证架构以保持其完整性,请在本地和 CI/CD 流水线中设置类似GraphQL Inspector 的工具。如果您使用 Apollo 生态系统,它内置于 Apollo Studio 或其提供的 CLI 工具中。
- 想要获得 ESLint 支持来强制执行标准并维护整个团队的理智,请尝试GraphQL ESLint之类的东西并使用您喜欢的约定进行设置。
- 设置graphql-config,它将与其他工具(例如 codegen、VSCode GraphQL 扩展、GraphQL ESLint 等)进行交互。这将非常有帮助,因为您只需一个配置即可管理所有接口工具。如果您使用的是 Apollo Stack,则可能还需要一个apollo-config
- 如果你想让你的 GraphQL 代码尽可能模块化,并支持依赖注入等功能,可以尝试GraphQL 模块
- 想要连接多个不同的数据源和集成,每个数据源都有各自的格式,但同时又能在其上进行开发,享受 GraphQL 带来的体验吗?不妨试试GraphQL Mesh之类的工具。
- 想要使用工具测试 GraphQL 端点吗?你可能需要Insomnia、 Postman、 Hoppscotch 或 VSCode REST Client之类的工具。
虽然我可以就此进行更多讨论,但它永远不会结束,因为生态系统太庞大且繁荣。
我使用 REACT/Angular/Vue/Web Components。如何将 GraphQL 集成到我的组件中?
同样,前端生态系统也很庞大,拥有自己的一套工具和库。
就我而言,我通常尝试在没有任何框架的情况下在前端工作(我使用Lit Elements,我们很快会有一个单独的博客),您使用的工具完全取决于您的要求。
- Apollo Client 确实与这些框架(包括React、iOS和Android)有很好的集成——所以,你可能想看看
- 使用 React?Relay可能是个不错的选择
- 使用 Vue?你可以尝试Vue Apollo
- 想将 Web 组件与 Apollo Stack 和 GQL 结合使用?不妨看看Apollo Elements
- 使用原生 JS 或 TS,或者使用 Web 组件,并希望拥有一种独立于框架的执行方式?您可以坚持使用 GraphQL 代码生成器本身,因为它几乎可以处理底层的所有工作。或者,如果您愿意,也可以使用 Apollo Client 的原生版本
@apollo/client/core
。Apollo Elements确实支持许多 Web 组件库,例如Lit、Fast和Gluon,甚至可以独立使用,因此非常灵活。 - 或者,如果您只是在寻找轻量级、高性能和可扩展的 GraphQL 客户端,URQL也非常适合。
- 或者,如果您正在寻找一个可以在浏览器和 Node 中运行的最小客户端,您可以尝试GraphQL Request
嗯,还有很多其他方法我们还没有讨论,这只是一个开始。
使用 GraphQL 时我可以通过哪些方式保持性能?
虽然 GraphQL 前景广阔且实用,但你必须明白,与任何技术或框架一样,它自身也存在一些问题,其中大多数问题已经得到解决。例如,你可能听说过 N+1 问题、缺乏缓存、查询成本和复杂性等等,这些问题已经由一些项目解决,例如Dataloader、持久查询、缓存等等,你可以根据自己的需求进行设置。
最终,这取决于您想要提供的灵活性程度。灵活性越高,成本就越高。具体如何选择,取决于您的用例。
尝试构建数据图架构时需要遵循哪些原则或标准?
一些出色的人已经在这里回答了这个问题,我强烈建议您在开始使用 GraphQL 之前先阅读一下。
如果你正在寻找有关 GraphQL 的规则和实现细节的帮助,你可以在这里找到一份很棒的文档
虽然所有这些原则都试图引导您朝着正确的方向前进,但请选择最适合您的用例的原则并加以运用。
如何使用 GraphQL 与多个数据源交互?
现实世界中实现这一点的一个很好的例子就是Gatsby,无论数据来源如何,所有内容最终都会通过插件转换为 GraphQL,然后可以在您的工作流程中使用。
如果您要在服务器端构建它,您可以使用开箱即用的解决方案(如GraphQL Mesh),也可以自行构建它,因为 GraphQL 只是充当顶层抽象。
或者如果你在 Apollo 堆栈上并且想要连接到多个数据源,你可以看看Apollo-datasource
或者你想拥有一个与 GraphQL 非常相似的 ORM,例如Prisma,以便与底层的多个数据库集成
最终一切都归结于如何构建解析器。
但这还不够。一些数据库也通过适配器或原生支持 GraphQL。
例如。
- Dgraph有一个原生的GraphQL实现
- Neo4j有一个GraphQL适配器
- Hasura在数据源之上提供了 GraphQL 抽象
- 如果你使用 Postgres, Postgraphile可以提供帮助
嗯,这些只是部分工具和服务。还有更多类似的工具和服务可以提供帮助。
GraphQL 规范缺少一些类型,例如 DateTime、GeoLocation 等。我该如何实现?
是的,这可能会很痛苦。但是,GraphQL 的设计初衷就是尽可能保持精简和轻量。
这正是GraphQL 标量真正发挥作用的地方。如果某些类型不支持开箱即用,您可以定义自己的类型,并在您的 schema 中使用它们。
但是,这可能很难实现,使用像graphql-scalars这样的包实际上可以有所帮助,因为它内置了一些可以导入和使用的常用标量。
我发现有些字段在不同的查询和修改之间重复出现。该如何避免这种情况?
按照DRY 原则,我们还可以借助GraphQL Fragments使我们的操作模块化,然后在任何地方使用这些片段。
我不能将我的数据库模式直接转换为 GraphQL 模式或生成 GraphQL 模式吗?
虽然从技术上讲,这是可能的,而且这也是在顶层提供 GraphQL 层的数据库提供商(如 Hasura 或 Graphcool)所使用的,但强烈不建议客户端使用,我也建议您阅读本文以获得更多想法。
我认为主要原因是 GraphQL 旨在描述围绕业务/领域术语的数据图,而不涉及底层的技术复杂性或细节。例如,我们不必关心特定字段来自哪个表、如何连接等等。
它应该只是针对最终用户的业务实现,因此即使不了解底层技术实现的产品经理也可以使用它。
因此,虽然你可以将 GraphQL 用作数据库或其他数据源的 ORM,但将其直接暴露给客户端并不是一个好选择。相反,应该在其上再增加一层,使其对任何最终用户都有意义,并降低客户端的复杂性。
是否有一些辅助库可用于处理我的 GraphQL 模式?
是的。GraphQL Tools(最初来自 Apollo,后来被 Guild 接管)是我强烈推荐的库之一。你可以对 SDL 或 schema 执行很多操作,例如合并多个 schema、使用测试数据模拟 schema、构建自定义指令、加载远程 schema 等等,这些都可以添加到你的技术栈中。
分发模式的最佳策略是什么?如果我使用带有 GraphQL 的微服务怎么办?
虽然 GraphQL 旨在成为单一端点,为客户端提供单一的统一数据视图,但通常无法在一个地方完成所有操作,因为这会造成很多瓶颈。因此,Schema 拼接或Apollo Federation应运而生,多个子 Schema 可以共同构成统一的数据图。
虽然我们可以在以后的某个时候就 Schema Stitching 与 Federation 分别写一篇博客,但每种方法都有其优点和缺点,只有您尝试过这两种方法才能理解。
这些视频可以帮助了解一些基础知识(但自从这些视频发布以来,很多事情都发生了变化,特别是随着 GraphQL Tools 引入类型合并):
如果您仍然不清楚该怎么做,您还可以阅读有关缝合和联合的博客。
有哪些值得关注的 GraphQL 活动/会议?
自 GraphQL 发布以来,它引起了社区的极大兴趣,世界各地举办了许多以 GraphQL 为主题的会议、活动和聚会。其中包括:
还有更多,包括像这样的聚会和这些。如果你搜索一下,就能在 YouTube 上找到之前大部分会议的录像。
我如何为 GraphQL 及其生态系统做出贡献?
GraphQL 基金会由一群志愿者运营,并且完全开源,因此每一份帮助都弥足珍贵。您可以
- 撰写这样的博客来在社区中传播知识
- 举办聚会,在会议上讲述您的经验并尽可能以最好的方式传播您的信息。
- 通过您的建议为GraphQL 规范做出贡献(有些建议即使是好的也可能需要数年才能实现,因此您可能需要对此有很大的耐心)
- 为 GraphQL 工具生态系统做出贡献,无论是文档、测试、功能、错误修复、反馈等等。这绝对有帮助。
- GraphQL 面临尚未解决的挑战?构建自己的工具并贡献给社区
- 创建失败测试和可重现的项目
- 在 Github Issues、Discord、Stack Overflow、Twitter 和 Reddit 上解答问题并提供帮助。有很多很棒的 GraphQL 社区。
- 或者,如果您想将其提升到一个新的水平,并希望让整个组织协调起来以帮助 GraphQL 基金会,那么请成为其成员并做出贡献。
有很多小事可以回馈社会。无论大小,都至关重要。每一点贡献都至关重要。
是否有一些案例研究可以真正帮助我实施?
当然。虽然我无法在这里全部列出,但以下是一些:
您可以在这里找到更多信息
是否有任何公开可用的 GraphQL API 可供我使用?
是的。虽然大多数应用都需要身份验证,但您仍然可以使用。以下是一些示例:
您可以在这里查看更多类似的内容并尝试一下。
我的组织中有一个遗留的架构/技术栈。如何逐步迁移到 GraphQL?
这是 GraphQL 真正闪耀的地方之一。你无需将所有东西都一次性迁移过来。以下是一些可能有帮助的步骤。
- 首先,为你的整个业务构建一个数据图,无需担心底层逻辑/实现。不过,也不必太担心,因为你可以随时改进它。
- 接下来,为架构的每个部分实现解析器,这样在第一阶段,您只需用 GraphQL 包装现有的基础架构即可。例如,如果您的服务使用 SOAP,您可以在其上添加一个 GraphQL 层,并调用该层来处理底层的所有 SOAP 服务,而客户端无需担心。您可以使用GraphQL Mesh或SOFA之类的工具来帮助抽象这些服务。这里有一篇关于如何从 REST 迁移到 GraphQL 的优秀博客文章。
- 逐个更改客户端实现以调用 GraphQL 网关而不是旧服务。
- 现在,您的生态系统中已经可以使用 GraphQL,您可以逐步摆脱 SOAP 等传统实现,而不必担心它将如何逐步影响客户端,一次一个组件地使用原生 GraphQL 实现。
虽然这是一种可行的方法,但并非唯一的方法。还有很多其他方法可以让你一步步实现这一目标,而不必担心遗留代码。
如何保护我的 GraphQL 端点?
虽然 GraphQL 规范本身并不推荐任何特定的方法来做到这一点,而是将其留给实现它的人,但你可以使用JWT、 Cookies 、 Sessions 等,就像你通过其他机制进行身份验证时通常所做的那样。
如何启用对我的 GraphQL 字段或模式的授权?
这在 GraphQL 中非常强大,因为您可以在非常细粒度的级别(无论是类型级别还是字段级别)进行授权。您可以阅读这篇博客,其中介绍了各种授权方法。
您也可以使用像GraphQL Shield这样的库,它提供了强大的中间件来实现这一点。但请记住,授权确实会带来附加成本,因为您需要在解析器中/之前为所有要授权的字段运行特定的逻辑。
一种经常被忽视的方法是使用指令进行授权,本文中提到了一个例子,它非常强大且具有声明性。通过这种方式,您可以指定范围并将指令添加到 SDL 中的相应字段,它就可以为您完成这项工作。
如何使用 GraphQL 在我的应用程序中启用聊天、自动更新等实时应用程序?
目前有一些选项可以实现这一点。
- 第一种是使用GraphQL 订阅,它是规范的一部分。如果你想这样做,你必须提前注册订阅,并且需要支持 Websockets。
- 另一种方法是进行定期的长时间轮询,它可以在小范围内工作,使您的应用程序保持无状态。
- 另一种方法是使用实时查询
每种方案都有各自的优缺点。请记住,如果您需要像订阅这样的功能,通常不可能保持应用程序无状态。因此,请确保妥善管理状态,并为故障和应用程序的扩展做好规划。
如果您是订阅新手,您可以观看此视频来了解订阅的基本工作原理。
我通过自省能做什么?
自省功能通常被工具用来理解你的 GraphQL 类型和模式。例如,像GraphQL Voyager这样的工具可以自省你的模式并构建出令人惊叹的图表,几乎所有基于 GraphQL 构建的扩展都利用了这种功能来理解你的模式、类型以及它周围的一切。
请注意,出于安全和性能原因,专家建议在生产中禁用自省功能。
如何追踪 GraphQL 中的所有操作?
您可以通过多种方式来实现这一点。
- 如果您想自己执行此操作,您可以使用Jaeger / Opentelemetry SDK 从解析器内部发送跟踪或上下文,并手动发送所有信息进行跟踪。
- Opentelemetry 最近推出了对 GraphQL 的支持。您可以在这里找到它
- 但是如果你发现自己正在使用 Apollo Stack,Apollo 有自己的跟踪选项,例如 Apollo Tracing,你可以在这里阅读相关内容
请记住,跟踪会导致大量的性能开销,强烈建议将其关闭,除非另有需要或可能仅将其用于特定关注层。
我该如何优雅地处理错误?
再次强调,有很多方法可以做到这一点。
- 如果您使用 Apollo 堆栈,则可以使用 apollo-errors 包,如此处所述
- 如果您使用 express-graphql 或想要原生使用 graphql-js,它们也会基于GraphQLError公开错误函数,并且还可以使用 GraphQL 扩展来增强自定义有效负载(如错误代码等),这些就是您在使用 graphql-helix 等服务器时通常会做的事情。
现在,情况就是这样,因为 GraphQL 不依赖于传输层,因此像 200、400 或 500 这样的状态代码可能没有意义,除非它们是响应的一部分,并且规范也没有规定执行此操作的具体方法。
GraphQL 是否与图形数据库有某种关联?
虽然 GraphQL 鼓励您将整个数据视为相互连接的信息图,因为这样可以更好地了解如何构建模式,从而形成统一的数据图,但它与图形数据库本身没有任何关系,因为图形数据库是一种在底层存储系统中表示和存储数据的方式,以实现快速遍历、行走和检索。
但话虽如此,GraphQL 和图数据库之间确实存在很多协同作用。你可以在这里和这里阅读相关内容,因为它们都与建立数据模式及其关系有关。
在向最终用户公开 REST API 时,我过去常常根据 API 调用次数向用户收费。对于 GraphQL,我该如何做到这一点?
这可能是 GraphQL 中的一个具有挑战性的问题,因为客户端决定查询/变异什么,而服务器可能无法提前知道这一点,除非您使用类似持久查询的东西。
在这里,CPU 的消耗可能取决于查询的嵌套层级、解析器执行的操作等等,这使得预先估算成本变得困难。您可以在此处找到详细的博客。
- 处理此问题的一种方法是仅允许持久查询并批准它们并预先为它们分配成本,但随着查询和突变数量的增加,从长远来看,这可能会变得难以管理。
- 另一种方法是使用自定义成本指令,就像在这个包中手动指定复杂性和成本并使用它来计费你的 API
这是一个相对较新的领域,仍在探索中。例如,Dgraph 根据访问的节点为 Slash GraphQL 计费,正如这里提到的,这对于使用 GraphQL 的数据库有效,但对于 GraphQL API 本身则不一定有效。
这里还有一些其他资源,它们也包含有关 GraphQL 的常见问题解答
还有更多。只需谷歌一下即可。
希望以上信息对您有所帮助。如果您还有任何我未涵盖的问题,或者需要帮助,欢迎通过@techahoy联系我。
如果觉得有帮助,请分享给你的朋友,也请继续关注我们,每周都会收到更多类似的文章。期待下次再见。
鏂囩珷鏉ユ簮锛�https://dev.to/timecampus/graphql-diving-deep-4hnm