16 分钟
The Graph客户端工具
这个仓库是The Graph消费者端工具(适用于浏览器和NodeJS环境)的家。
背景
本节提供的工具旨在丰富和扩展DX, 并添加 dApp 所需的附加层以实现分布式应用程序。
从GraphQL API 上[The Graph 消耗数据的开发者常常需要外观才能使数据消耗更加容易, 而且还可以同时使用多个索引人的工具。
特征和目标
这个库旨在简化dApp数据消耗的网络方面。 这个仓库中提供的工具是为了在构建时运行,以便在运行时更快地执行和运行。
在这个仓库中提供的工具可以单独使用,但你也可以和任何现有的 GraphQL 客户端一起使用!
状态 | 特征 | 注意: |
---|---|---|
✅ | 多个索引人 | 基于获取策略 |
✅ | 获取策略 | 超时、 重试、 回退、 种族,最高值 |
✅ | 构建时间验证和优化 | |
✅ | 客户端组成 | 改进执行规划程序(基于 GraphQL-Mesh) |
✅ | 跨链子图处理 | 使用相似子图作为单个源 |
✅ | 原始执行 (独立模式) | 没有包装GraphQL客户端 |
✅ | 本地(客户端) 突变 | |
✅ | 自动区块跟踪 | 跟踪区块编号 如这里描述的 |
✅ | 自动分页 | 在单次调用中执行多个请求以获取超过索引人限制的数据 |
✅ | 与 @apollo/client 集成 | |
✅ | 与 urql 集成 | |
✅ | TypeScript 支持 | 具有内置的 GraphQL Codegen 和 TypedDocumentNode |
✅ | @live 查询 | 基于投票 |
您可以在这里找到一个扩展架构设计。
开始
您可以关注 Episode 45 of graphql.wtf
来了解更多关于Graph客户端的信息:
若要启动,请确保在您的项目中安装 [The Graph客户端CLI] :
1yarn add -D @graphprotocol/client-cli2# or, with NPM:3npm install --save-dev @graphprotocol/client-cli
CLI 是作为dev 依赖安装的,因为我们正在使用它来产生优化的运行时工件,这些工件可以直接从您的应用中加载!
创建一个配置文件 (名为 .graphclientrc.yml
) 并指向您的由The Graph提供的GraphQL 端点, 例如:
1# .graphclientrc.yml2sources:3 - name: uniswapv24 handler:5 graphql:6 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2
现在,通过运行 The Graph客户端 CLI 创建运行时的工件:
1graphclient build
注意:您需要使用 yarn
前缀运行此操作,或者在您的 package.json
中添加一个脚本。
这将产生一个可随时使用的独立执行
函数。 你可以用来运行你的应用程序 GraphQL 操作,你应该有一个类似于以下的输出:
1GraphClient: Cleaning existing artifacts2GraphClient: Reading the configuration3🕸️: Generating the unified schema4🕸️: Generating artifacts5🕸️: Generating index file in TypeScript6🕸️: Writing index.ts for ESM to the disk.7🕸️: Cleanup8🕸️: Done! => .graphclient
现在,.graphclient
的艺术品是为你生成的,你可以直接从你的代码中导入它,并运行你的查询:
1import { execute } from '../.graphclient'23const myQuery = gql`4 query pairs {5 pair(id: "0x00004ee988665cdda9a1080d5792cecd16dc1220") {6 id7 token0 {8 id9 symbol10 name11 }12 token1 {13 id14 symbol15 name16 }17 }18 }19`2021async function main() {22 const result = await execute(myQuery, {})23 console.log(result)24}2526main()
使用 Vanilla JavaScript 而不是 TypeScript
GraphClient CLI 默认情况下以 TypeScript 文件生成客户端工件, 但您可以使用 --fileType js
或 --fileType js
或 --fileType json
来配置 CLI 以生成JavaScript 和 JSON 文件以及额外的 TypeScript 定义文件。
js
标志生成了所有使用 JavaScript 文件的文件,其中含有ESM 语法和 json
标志作为JSON 文件生成了源代码,同时也生成了旧的 CommonJS 语法的 JavaScript 文件,因为只有CommonJS支持 JSON 文件作为模块。
除非您使用CommonJS(require
),否则我们建议您使用js
标记。
graphclient --fileType js
The Graph客户端开发工具
The Graph客户端CLI 带有内置的 GraphiQL,因此您可以实时尝试查询。
在这种环境下服务的 GraphQL 模式是基于您应用的所有构成子图和转换的最终模式 。
要启动DevTool GraphiQL,请运行以下命令:
1graphclient serve-dev
然后打开 http://localhost:4000/以使用 GraphiQL。您现在可以在本地试用您的Graph客户端GraphQL 模式!🥳
例子
您还可以参考此仓库中的示例目录,了解更高级的示例和集成示例:
- [TypeScript & React示例与原始的
execute
和内置的 GraphQL-Codegen - TS/JS NodeJS独立模式
- 客户端 GraphQL 组合
- 与Urql 和 React集成
- 与NextJS 和 TypeScript集成
- 与Apollo-Client 和 React集成
- 与React-Query集成
- 跨链合并 (相同的子图,不同的链)
- 使用Transforms(自动分页和自动块跟踪)自定义执行
高级示例/功能
自定义网络调用
您可以使用operationHeaders
自定义网络执行 (例如,添加身份验证头):
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 operationHeaders:7 Authorization: Bearer MY_TOKEN
如果您愿意,您也可以使用运行时变量,并以声明方式指定:
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 operationHeaders:7 Authorization: Bearer {context.config.apiToken}
然后,您可以指定当您执行操作时:
1execute(myQuery, myVariables, {2 config: {3 apiToken: 'MY_TOKEN',4 },5})
您可以在这里找到 graphql
处理程序的完整文档。
环境变量内插值
如果你想要在你的Graph客户端配置文件中使用环境变量,你可以使用 env
助手的插值:
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 operationHeaders:7 Authorization: Bearer {env.MY_API_TOKEN} # runtime
然后,请确保在运行process.env
时定义MY_API_TOKEN
。
您还可以直接使用 Env-var 名称指定要在构建时间(在 graphclient build
运行时) 填充的环境变量:
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 operationHeaders:7 Authorization: Bearer ${MY_API_TOKEN} # build time
您可以在这里找到 graphql
处理程序的完整文档。
获取策略和多图索引人
在dApp中使用多个索引人是一种常见的做法,以便实现理想的The Graph体验, 你可以指定 fetch
的几种策略来使它更加顺畅和简单。
所有的 fetch
策略可以合并来创建最终的执行流程。
"重试"
重试
机制允许您指定重试单个GraphQL端点/源的尝试。
重试将在两个条件下执行:网络错误或运行时错误(索引问题/索引人不可用)。
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 retry: 2 # specify here, if you have an unstable/error prone indexer
"超时"
超时
机制允许您为给定的 GraphQL 端点指定超时
。
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 timeout: 5000 # 5 seconds
“fallback”
fallback
机制允许您为同一来源指定多个GraphQL端点。
如果您想要为同一个子图使用多个索引人,并在发生错误/超时时时进行回退,这是有用的。 您也可以使用此策略来使用自定义索引人,但允许它回退到 The Graph托管服务。
1sources:2 - name: uniswapv23 handler:4 graphql:5 strategy: fallback6 sources:7 - endpoint: https://bad-uniswap-v2-api.com8 retry: 29 timeout: 500010 - endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2
"竞技"
“种族”机制允许您为同一源指定多个GraphQL端点,以及每次执行时的竞赛。
如果你想要在同一个子图中使用多个索引人,这是有用的, 并且允许这两个来源进行竞赛,并从所有指定的索引人获得最快的响应。
1sources:2 - name: uniswapv23 handler:4 graphql:5 strategy: race6 sources:7 - endpoint: https://bad-uniswap-v2-api.com8 - endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2
"最高值"
此策略允许您将并行请求发送到同一源的不同端点并选择最先进的端点。
如果您想要从不同的索引人/源选择同一子图中最常同步的数据,这是有用的。
1sources:2 - name: uniswapv23 handler:4 graphql:5 strategy: highestValue6 strategyConfig:7 selectionSet: |8 {9 _meta {10 block {11 number12 }13 }14 }15 value: '_meta.block.number'16 sources:17 - endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2-118 - endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2-2
区块跟踪
Graph客户端可以跟踪块号码并通过 blockTracking
转换通过 此模式进行以下查询:
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 transforms:7 - blockTracking:8 # You might want to disable schema validation for faster startup9 validateSchema: true10 # Ignore the fields that you don't want to be tracked11 ignoreFieldNames: [users, prices]12 # Exclude the operation with the following names13 ignoreOperationNames: [NotFollowed]
自动分页
对大多数子图,您可以获取的记录数量是有限的。在这种情况下,您必须发送多个带分页的请求。
1query {2 # Will throw an error if the limit is 10003 users(first: 2000) {4 id5 name6 }7}
所以你必须一个接一个的发送操作:
1query {2 # Will throw an error if the limit is 10003 users(first: 1000) {4 id5 name6 }7}
然后在第一个响应之后:
1query {2 # Will throw an error if the limit is 10003 users(first: 1000, skip: 1000) {4 id5 name6 }7}
在第二个响应后,您必须手动合并结果。 但是The Graph客户端允许您做第一个,并自动为您在场景下执行这些多个请求。
您必须做的是:
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 transforms:7 - autoPagination:8 # You might want to disable schema validation for faster startup9 validateSchema: true
客户端组成
The Graph客户端内置支持客户端GraphQL组成(由 GraphQL-Tools Schema-Stitching驱动)。
您可以利用此功能,从多个子图中创建一个单一的 GraphQL 层,部署在多个索引人。
💡 提示: 你可以创建任何GraphQL源, 而不仅仅是子图!
可通过将多个GraphQL源添加到您的 .graphclientrc.yml
文件来完成三角合成,下面是一个示例:
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 - name: compoundv27 handler:8 graphql:9 endpoint: https://api.thegraph.com/subgraphs/name/graphprotocol/compound-v2
只要在合成模式之间没有冲突,您就可以编写它,然后对两个子图执行一个查询:
1query myQuery {2 # this one is coming from compound-v23 markets(first: 7) {4 borrowRate5 }6 # this one is coming from uniswap-v27 pair(id: "0x00004ee988665cdda9a1080d5792cecd16dc1220") {8 id9 token0 {10 id11 }12 token1 {13 id14 }15 }16}
您也可以解决冲突,重命名模式的一部分,添加自定义 GraphQL 字段,并修改整个执行阶段。
关于由人员组成的高级使用案例,请参考以下资源:
- Advanced Composition Example
- GraphQL-Mesh Schema transformations
- GraphQL-Tools Schema-Stitching documentation
TypeScript 支持
如果你的项目是在TypeScript写的,你可以利用TypedDocumentNode
的力量,并且拥有一个完整的GraphQL客户端体验。
The standalone mode of The GraphQL, and popular GraphQL client libraries like Apollo-Client and urql has built-in support for TypedDocumentNode
!
The Graph客户端CLI带有一个现成配置的 GraphQL 代码生成器,它可以根据您的 GraphQL 操作生成TypedDocumentNode
。
要启动,请在应用程序代码中定义您的 GraphQL 操作,并指向使用 .graphclientrc.yml
中的 documents
部分的文件:
1sources:2 - # ... your Subgraphs/GQL sources here34documents:5 - ./src/example-query.graphql
您也可以使用 Glob 表达式,甚至指向代码文件,CLI 会自动找到您的 GraphQL 查询:
1documents:2 - './src/**/*.graphql'3 - './src/**/*.{ts,tsx,js,jsx}'
现在,再次运行 GraphQL CLI build
命令,CLI 将在.graphclient
下为找到的每个操作生成一个 TypedDocumentNode
对象。
请务必命名您的 GraphQL 操作,否则将被忽略!
例如,一个叫做query ExampleQuery
的查询将在.graphclient
中生成相应的ExampleQueryDocument
。 您现在可以导入它并用于您的 GraphQL 调用, 您将拥有完整类型的体验,无需手动写入或指定任何类型脚本:
1import { ExampleQueryDocument, execute } from '../.graphclient'23async function main() {4 // "result" variable is fully typed, and represents the exact structure of the fields you selected in your query.5 const result = await execute(ExampleQueryDocument, {})6 console.log(result)7}
你可以在这里找到一个TypeScript项目示例。
客户端突变
由于Graph-客户端设置的性质,可以添加客户端模式,您以后可以通过桥接运行任意代码。
这很有帮助,因为您可以实现自定义代码作为您的 GraphQL 模式的一部分, 让它作为统一的应用程序模式更容易跟踪和发展。
本文档解释了如何添加自定义突变,但事实上,您可以添加任何GraphQL操作(查询/突变/订阅)。请参阅扩展统一模式文章获取有关此功能的更多信息。
要启动,请在配置文件中定义一个 additionalTypeDefs
部分:
1additionalTypeDefs: |2 # We should define the missing `Mutation` type3 extend schema {4 mutation: Mutation5 }67 type Mutation {8 doSomething(input: SomeCustomInput!): Boolean!9 }1011 input SomeCustomInput {12 field: String!13 }
然后,在自定义GraphQL解析器文件中添加指针:
1additionalResolvers:2 - './resolvers'
现在,在你的项目中创建 resolver.js
(或resolvers.ts
),并实现你的自定义突变:
1module.exports = {2 Mutation: {3 async doSomething(root, args, context, info) {4 // Here, you can run anything you wish.5 // For example, use `web3` lib, connect a wallet and so on.67 return true8 },9 },10}
如果您正在使用 TypeScript,您也可以通过以下操作获得完全安全类型的签名:
1import { Resolvers } from './.graphclient'23// Now it's fully typed!4const resolvers: Resolvers = {5 Mutation: {6 async doSomething(root, args, context, info) {7 // Here, you can run anything you wish.8 // For example, use `web3` lib, connect a wallet and so on.910 return true11 },12 },13}1415export default resolvers
如果您需要将运行时变量注入到您的 GraphQL 执行context
中,您可以使用以下代码:
1execute(2 MY_QUERY,3 {},4 {5 myHelper: {}, // this will be available in your Mutation resolver as `context.myHelper`6 },7)
许可协议
在 MIT license下发布。