GraphQL 入门: Apollo Client - 持久化GraphQL查询概要

GraphQL 入门: 简介
GraphQL 入门: Apollo Client - 简介
GraphQL 入门: Apollo Client - 安装和配置选项
GraphQL 入门: Apollo Client - 连接到数据
GraphQL 入门: Apollo Client - 网络层
GraphQL 入门: Apollo Client - 开发调试工具
GraphQL 入门: Apollo Client - 持久化GraphQL查询概要
GraphQL 入门: Apollo Client - 存储API
GraphQL 入门: Apollo Client - 查询(Batching)合并

摘要: 本文采用 Elixir 语言开发的 Absinthe 作为 GraphQL 的服务器端实现,使用 Javascript 语言开发的 Apollo Client 作为 GraphQL 的客户端实现.

1. 持久化查询的概念

持久化查询,是一种避免客户端直接在查询请求中包含查询文档的一种方式,客户端只需要传递给要执行查询的ID,服务器通过ID查询到GraphQL文档,并在服务器端执行的过程.

优缺点:

客户端发送一个巨大的查询过量消耗服务器的资源

客户端可以执行任意查询,容易导致安全问题

使用持久化查询的目的:

  • 避免了客户端发送GraphQL文档,减少网络流量

  • 由于GraphQL巨大的灵活性,这也给安全带来了挑战,这种机制实际上就是查询白名单. 只有在白名单中的查询才是能被服务器执行的.

从直接发送查询文档转换到持久化查询的效果:

发送一个巨大的查询不再是一个问题

客户端只能查询服务器支持的限制性的GraphQL查询(通过ID)

2. 要求

客户端需要使用到 persistgraphql 工具来生成对应的查询描述文档. 用于完成查询到ID的映射关系.

服务器端也需要做同样的事情.

3. 实施方案

本节描述了服务器端和客户端的具体实现.

3.1. 服务器端

  • 服务器端采用Elixir语言作为开发语言和运行环境

  • 采用 Absinthe 包作为 GraphQL 查询的处理模块

  • 服务器端使用 Absinthe.Plug.DocumentProvider.Compiled 模块读取由 persistgraphql 工具生成的extracted_queries.json文件来达到和客户端一致.

3.1.1. 服务器端查询转换原理

服务器接收到客户端发过来的查询如下:

{
  id: < 查询 ID >,variables: < 变量JSON对象 >,}

通过查找ID,把查询转换为如下形式,把ID替换为查询文本:

{
  query: < GraphQL文档 >,variables: < 变量JSON对象 >
}

3.1.2. 实现细节

创建一个文档Provider:

defmodule MyApp.ExtractedQueryProvider do
  use Absinthe.Plug.DocumentProvider.Compiled

  provide File.read!("/path/to/extracted_queries.json")
  |> Poison.decode!
  |> Map.new(fn {k,v} -> {v,k} end) # invert key/value
end

添加该文档 Provider 到 Absinthe.Plug 配置:

plug Absinthe.Plug,schema: MyApp.Schema,document_providers: [
    Absinthe.Plug.DocumentProvider.Default,MyApp.ExtractedQueryProvider
  ]

当构建服务器端项目的时候,读取 extracted_queries.json 文件的内容,解析,并编译为Elixir模块,转换为中间表示,并执行验证. 这样的持久化查询请求就像通过ID请求一个普通的对象一样.

注意:
详细的服务器实现方法,请参考这个 Issue
另外Absinthe对持久化查询的支持需要用到最新的代码,请使用 absinthe_plugv1.3.0-alpha.0 及以上版本.

3.2. 客户端

本节描述了持久化查询的客户端实现.

3.2.1 基本原理

客户端通过读取 extracted_queries.json 文件,把读取到的文件内容转换为一个JSON对象,客户端向服务器发送请求之前,先通过把整个GraphQL查询作为对象的字符串Key,去找到对应的ID,通过查找到的ID去执行GraphQL查询.

这个GraphQL查询文本查询ID映射的JSON对象格式如下:

{
 < print(transform(GraphQL Document)) >: < ID >,}

Javascript 只允许字符串和数字作为键,因此我们通过 graphql-js 模块的 print 函数来解决这个问题.

最终,客户端通过下面的伪代码执行 GraphQL 查询:

query(request: Request) {
 // 在 request.query 结构中查找对应的ID
 // 找到对应的ID
 // 通过GraphQL查询变量把ID传递给服务器
 // 返回一个Promise对象用于获取服务器的返回结果
}

3.2.2 实现细节

安装 persistgraphql 命令行工具:

npm install --save persistgraphql 
# 或
yarn add persistgraphql
# 全局安装
yarn global add persistgraphql

persistgraphql 有两个命令行参数,分别表示输入和输出,输入可以是当个文件或者目录名称,路径可以使相对或绝对路径,安装好后,可以执行:

persistgraphql queries.graphql

生成 extracted_queries.json 文件. 如果指定的输入是一个目录,那么 persistgraphql 会去查找该目录下的所后缀为 .graphql 的文件. 你可以用GitHunt-React 这个项目来实际练习一下.

git clone git@github.com:apollographql/GitHunt-React.git
cd GitHunt-React
persistgraphql ui/graphql extracted_queries.json

客户的实现方法可参考资料: 使用Apollo Client持久化GraphQL查询

4. 参考资料

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom