持久化查询
在最小化请求延迟的同时保护您的图
Apollo 支持两个互相独立但相关的功能,称为 自动持久化查询 (APQs) 和 持久化查询。使用这两个功能,客户端可以发送一个操作 ID 而不是整个操作字符串来执行 GraphQL 操作。一个操作 ID 是整个操作字符串的散列值。通过 ID 查询可以显著降低大型操作字符串的延迟和带宽使用。
持久化查询与APQ之间的区别
持久化查询功能要求将 操作 注册到 持久化查询列表 (PQL)。这样,PQL 就可以作为一个由您的第一方应用程序创建的操作白名单。因此,持久化查询既是性能特性,也是安全特性。
对于 APQs,如果服务器找不到客户端提供的操作 ID,服务器将返回一个错误,表示需要完整的操作字符串。如果 Apollo 客户端收到此错误,它将自动使用完整的操作字符串重新尝试操作。
如果您只想改善请求延迟和带宽使用,APQ 满足您的需求。如果您还想通过操作白名单来保护您的 supergraph,应在 PQL 中注册操作。
有关持久化查询和 APQ 之间区别的更多详细信息,请参阅 GraphOS 持久化查询文档。
实施步骤
持久化查询和 APQ 都需要您配置代码生成和客户端如何发起请求。如果您打算将持久化查询用于名单管理,还需要生成一个 操作清单。
在实施时,我们建议您按照以下顺序操作
实施步骤 | 需要 PQ 吗? | 需要 APQ 吗? |
---|---|---|
1. 配置生成的操作模型 | ✅ | ✅ |
2. 生成操作清单 | ✅ | -- |
3. 发布操作清单 | ✅ | -- |
4. 在客户端发起请求时启用持久化查询 | ✅ | ✅ |
本文的其余部分详细阐述了这些步骤。
持久化查询还需要您创建并连接一个 PQL,以及配置您的 router以接收 持久化查询请求。本 文档仅描述客户端创建操作清单并发送持久化查询请求所需的步骤。有关持久化查询其他配置方面的更多信息,请参阅 GraphOS 持久化查询文档。
0. 要求
您可以将 APQ 与以下版本的 Apollo iOS、Apollo Server 和 Apollo Router Core 一起使用:
- Apollo iOS (v1.0.0+)
- Apollo Server (v1.0.0+)
- Apollo Router Core (v0.1.0+)
注意:您可以使用 任选一种 Apollo Server 或 Apollo Router Core 用于 APQ。它们不需要一起使用。
使用持久化查询进行名单管理有以下要求:
- Apollo iOS (v1.4.0+)
- GraphOS Router (v1.25.0+)
- GraphOS 企业计划
1. 配置生成的操作模型
持久化查询和 APQ 都需要在您的代码生成中包含 操作 ID。您可以在代码生成配置的 options
中进行配置。具体来说,将 operationDocumentFormat
数组设置为 definition
、operationId
或两者都为 definition
和 operationId
。
- 要使用 APQs,您必须同时包含
definition
和operationId
。 - 对于持久化查询,您只需要
operationId
。
"options": {"operationDocumentFormat" : ["definition","operationId"]}
2. 生成操作清单
此步骤仅适用于实现持久化查询的whitelisting。对APQs不需要此步骤。
操作清单是可信操作的安全列表,GraphOS Router 可以用它来检查传入请求。您可以通过将 GraphOS Router 添加到您的 ApolloCodegenConfiguration
JSON 文件中,以生成操作清单。
"operationManifest" : {"generateManifestOnCodeGeneration" : false,"path" : "/operation/identifiers/path","version" : "persistedQueries"}
一旦配置了这些选项,您可以通过运行 generate-operation-manifest
来生成操作清单。如果您将 generateManifestOnCodeGeneration
标志设置为 true
,则每次运行 generate
命令时,也会生成操作清单。
持久化查询的结果为操作清单如下:
{"format": "apollo-persisted-query-manifest","version": 1,"operations": [{"id": "e0321f6b438bb42c022f633d38c19549dea9a2d55c908f64c5c6cb8403442fef","body": "query GetItem { thing { __typename } }","name": "GetItem","type": "query"}]}
要自动更新每个新应用的清单,您可以在您的CI/CD管道中包含generate
或generate-operation-manifest
命令。
3. 发布操作清单
此步骤仅适用于实现持久化查询的whitelisting。对APQs不需要此步骤。
💡 提示
请确保您的 Rover CLI 版本是0.17.2
或更高版本。Rover的早期版本不支持将操作发布到PQL。下载最新版本。
生成操作清单后,您可以使用Rover CLI将其发布到您的PQL,如下所示:
rover persisted-queries publish my-graph@my-variant \--manifest ./persisted-query-manifest.json
- 命令中的
my-graph@my-variant
参数是PQL链接到的任何graph ref
的引用。- 图引用的格式为
graph-id@variant-name
。
- 图引用的格式为
- 使用
--manifest
选项提供要发布的清单的路径。
ⓘ 注意
该 持久化请求数据发布
命令假设清单以由 Apollo 客户端工具生成的 格式 存在。该命令还支持由 Apollo client 工具生成的 Relay 编译器 格式。您可以通过添加 --manifest-format relay
参数来实现。您的 Rover CLI 版本必须为 0.19.0 或更高版本才能使用此参数。
该 持久化请求数据发布
命令执行以下操作:
将提供的清单文件中的所有操作发布到与指定变体关联的 PQL,或发布到指定的 PQL。
- 将清单发布到 PQL 是累加的。PQL 中的任何现有条目都保留。
- 如果您发布了一个与 PQL 中的现有条目具有相同
id
但详细信息不同的操作,整个发布命令将因错误而不能成功。
更新应用了此 PQL 的任何其他 变体,以便与这些变体关联的 路由器 可以获取它们更新的 PQL。
与 生成清单 一样,最好在您的 CI/CD 管道上执行此命令,以便在应用程序发布过程发布新的操作。提供给 Rover 的 API 密钥必须具有 角色,即 Graph Admin 或 Persisted Query Publisher 。 Persisted Query Publisher 是专为与 rover persisted-queries publish
命令一起使用而设计的特别角色;具有此角色的 API 密钥对您在 GraphOS 中的图数据没有其他访问权限,并且适用于与可以发布到您的图 PQL 的受信任第三方客户端开发者共享,但他们不应以此以外的方式访问您的图。
测试操作
您可以发送一些测试 operations 以确保您已成功发布了您的清单:
首先,启动您的 GraphOS 连接的 router:
APOLLO_KEY="..." APOLLO_GRAPH_REF="..." ./router --config ./router.yaml2023-05-11T15:32:30.684460Z INFO Apollo Router v1.18.1 // (c) Apollo Graph, Inc. // Licensed as ELv2 (https://go.apollo.dev/elv2)2023-05-11T15:32:30.684480Z INFO Anonymous usage data is gathered to inform Apollo product development. See https://go.apollo.dev/o/privacy for details.2023-05-11T15:32:31.507085Z INFO Health check endpoint exposed at http://127.0.0.1:8088/health2023-05-11T15:32:31.507823Z INFO GraphQL endpoint exposed at http://127.0.0.1:4000/ 🚀
然后使用以下方式通过 curl 发起一个 POST 请求:
curl https://127.0.0.1:4000 -X POST --json \'{"extensions":{"persistedQuery":{"version":1,"sha256Hash":"dc67510fb4289672bea757e862d6b00e83db5d3cbbcfb15260601b6f29bb2b8f"}}}'
如果你的路由器's PQL包括一个与提供的sha256Hash属性值匹配的操作,它将执行相应的操作并返回其结果。
4. 在ApolloClient
上启用持久查询
一旦你已配置代码生成包括:操作ID,你就可以通过操作查询ID而不是完整的操作字符串来更新你的客户端。此配置无论是使用APQ还是持久查询都是相同的:
- 使用设置autoPersistQueries参数为true的RequestChainNetworkTransport初始化一个自定义的NetworkTransport,并包含一个包含AutomaticPersistedQueryInterceptor(例如DefaultInterceptorProvider)的interceptorProvider。
- 使用支持持久查询的自定义NetworkTransport初始化你的ApolloClient。
let store = ApolloStore(cache: InMemoryNormalizedCache())let interceptorProvider = DefaultInterceptorProvider(store: store)let networkTransport = RequestChainNetworkTransport(interceptorProvider: interceptorProvider,endpointURL: URL(string: "https://127.0.0.1:4000/graphql")!,autoPersistQueries: true)let client = ApolloClient(networkTransport: networkTransport, store: store)
有关配置你的ApolloClient, NetworkTransport, InterceptorProvider以及请求链的更多信息,请参阅请求处理管道文档。
作为GET
请求发送APQ重试请求
注意:Apollo iOS只针对APQ重试失败的基于ID的操作,而不仅仅是持久查询。
默认情况下,Apollo客户端以POST
请求发送操作重试。在某些情况下,你可能希望或需要使用GET
请求重试操作:例如,你可能需要向具有更好性能的CDN发出请求。
要使用GET用于APQ重试请求,将你的RequestChainNetworkTransport上的useGETForPersistedQueryRetry设置为true。
在大多数情况下,保持默认选项(false)就足够了。