12 minutes
Les outils de The Graph Client
Ce répertoire abrite les outils côté consommateur de The Graph (pour les environnements navigateur et NodeJS).
Contexte
Les outils fournis dans ce repo sont destinés à enrichir et à étendre le DX, et à ajouter la couche supplémentaire requise pour les dApps afin de mettre en œuvre des applications distribuées.
Les développeurs qui consomment des données à partir de The Graph GraphQL API ont souvent besoin de périphériques pour faciliter la consommation des données, ainsi que d’outils permettant d’utiliser plusieurs Indexeurs en même temps.
Fonctionnalités et objectifs
Cette bibliothèque est destinée à simplifier l’aspect réseau de la consommation de données pour les dApps. Les outils fournis dans ce dépôt sont destinés à être exécutés au moment de la construction, afin de rendre l’exécution plus rapide et plus performante au moment de l’exécution.
Les outils fournis dans ce repo peuvent être utilisés de manière autonome, mais vous pouvez également les utiliser avec n’importe quel client GraphQL existant !
Status | Fonctionnalité | Notes |
---|---|---|
✅ | Indexeurs multiples | sur la base de stratégies d’extraction |
✅ | Stratégies d’extraction | timeout, retry, fallback, race, highestValue |
✅ | Validations et optimisations du temps de construction | |
✅ | Composition côté client | avec un planificateur d’exécution amélioré (basé sur GraphQL-Mesh) |
✅ | Gestion des subgraphs multi-chaînes | Utiliser des subgraphs similaires comme source unique |
✅ | Exécution brute (mode autonome) | sans client GraphQL intégré |
✅ | Mutations locales (côté client) | |
✅ | Suivi automatique des blocs | les numéros de blocs de suivi tels que décrits ici |
✅ | Pagination automatique | effectuer plusieurs requêtes en un seul appel pour récupérer plus que la limite de l’Indexeur |
✅ | Intégration avec @apollo/client | |
✅ | Intégration avec urql | |
✅ | Prise en charge de TypeScript | avec GraphQL Codegen et TypedDocumentNode intégrés |
✅ | @live queries | Sur la base de sondages |
Vous pouvez trouver un modèle d’architecture étendu ici
Introduction
Vous pouvez suivre [l’épisode 45 de graphql.wtf
] (https://graphql.wtf/episodes/45-the-graph-client) pour en savoir plus sur Graph Client :
Pour commencer, assurez-vous d’installer [The Graph Client CLI] dans votre projet :
1yarn add -D @graphprotocol/client-cli2# or, with NPM:3npm install --save-dev @graphprotocol/client-cli
La CLI est installé en tant que dépendance dev puisque nous l’utilisons pour produire des artefacts d’exécution optimisés qui peuvent être chargés directement à partir de votre application !
Créez un fichier de configuration (appelé .graphclientrc.yml
) et pointez vers vos endpoints GraphQL fournis par The Graph, par exemple :
1# .graphclientrc.yml2sources:3 - name: uniswapv24 handler:5 graphql:6 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2
Maintenant, créez un artefact d’exécution en exécutant The Graph Client CLI:
1graphclient build
Note : vous devez exécuter ceci avec le préfixe yarn
, ou ajouter ce script dans votre package.json
.
Cela devrait produire une fonction autonome execute
prête à l’emploi, que vous pouvez utiliser pour exécuter les opérations GraphQL de votre application, vous devriez obtenir une sortie similaire à la suivante :
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
Maintenant, l’artefact .graphclient
est généré pour vous, et vous pouvez l’importer directement depuis votre code, et lancer vos requêtes :
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()
Utiliser Vanilla JavaScript au lieu de TypeScript
GraphClient CLI génère par défaut les artefacts du client sous forme de fichiers TypeScript, mais vous pouvez configurer la CLI pour générer des fichiers JavaScript et JSON ainsi que des fichiers de définition TypeScript supplémentaires en utilisant --fileType js
ou --fileType json
.
L’option js
génère tous les fichiers en tant que fichiers JavaScript avec la syntaxe ESM et l’option json
génère les artefacts source en tant que fichiers JSON tandis que le fichier JavaScript du point d’entrée avec l’ancienne syntaxe CommonJS parce que seul CommonJS supporte les fichiers JSON en tant que modules.
A moins que vous n’utilisiez CommonJS (require
) spécifiquement, nous vous recommandons d’utiliser le l’option js
.
graphclient --fileType js
- Un exemple d’utilisation de JavaScript dans la syntaxe CommonJS avec des fichiers JSON
- Un exemple d’utilisation de JavaScript dans la syntaxe ESM
Le DevTools The Graph Client
La CLI de The Graph Client est dotée d’une interface GraphiQL intégrée, ce qui vous permet d’expérimenter des requêtes en temps réel.
Le schéma GraphQL servi dans cet environnement est le schéma final basé sur tous les subgraphs composés et les transformations que vous avez appliquées.
Pour lancer Le DevTool GraphiQL, exécutez la commande suivante :
1graphclient serve-dev
Et ouvrez http://localhost:4000/ pour utiliser GraphiQL. Vous pouvez maintenant expérimenter votre schéma GraphQL côté client localement ! 🥳
Exemples
Vous pouvez également vous référer aux répertoires examples dans ce repo, pour des exemples plus avancés et des exemples d’intégration :
- Exemple TypeScript & React avec un
execute
brut et GraphQL-Codegen intégré - TS/JS NodeJS standalone mode
- Composition GraphQL côté client
- Intégration avec Urql et React
- Intégration avec NextJS et TypeScript
- Intégration avec Apollo-Client et React
- Intégration avec React-Query
- Fusion interchain (même subgraph, blockchains différentes)
- Personnaliser l’exécution avec Transforms (auto-pagination et auto-block-tracking)
Exemples/fonctionnalités avancés
Personnaliser les appels réseau
Vous pouvez personnaliser l’exécution du réseau (par exemple, pour ajouter des en-têtes d’authentification) en utilisant 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
Vous pouvez également utiliser des variables d’exécution si vous le souhaitez, et les spécifier de manière déclarative :
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}
Vous pouvez ensuite le spécifier lorsque vous exécutez des opérations :
1execute(myQuery, myVariables, {2 config: {3 apiToken: 'MY_TOKEN',4 },5})
Vous pouvez trouver la documentation complète du gestionnaire graphql
ici.
Interpolation des Variables d’environnement
Si vous souhaitez utiliser des variables d’environnement dans votre fichier de configuration Graph Client, vous pouvez utiliser l’interpolation avec l’assistant 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
Ensuite, assurez-vous que MY_API_TOKEN
est défini lorsque vous lancez process.env
au moment de l’exécution.
Vous pouvez également spécifier des variables d’environnement à remplir au moment de la construction (pendant l’exécution de graphclient build
) en utilisant directement le nom env-var :
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} # temps de construction
Vous pouvez trouver la documentation complète du gestionnaire graphql
ici.
Extraire les Stratégies et les multiples Indexeurs de The Graph
C’est une pratique courante d’utiliser plus d’un Indexeur dans les dApps, donc pour obtenir l’expérience idéale avec The Graph, vous pouvez spécifier plusieurs stratégies fetch
afin de rendre les choses plus fluides et plus simples.
Toutes les stratégies fetch
peuvent être combinées pour créer le flux d’exécution ultime.
`retry`
Le mécanisme (retry)réessai
vous permet de spécifier les tentatives de réessais pour un seul endpoint/source GraphQL.
The retry flow will execute in both conditions: a netword error, or due to a runtime error (indexing issue/inavailability of the indexer).
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 retry: 2 # spécifier ici, si vous avez un Indexeur instable ou sujet à des erreurs
`timeout`
Le mécanisme timeout
vous permet de spécifier le timeout
pour un endpoint GraphQL donné.
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 timeout: 5000 # 5 secondes
`fallback`
Le mécanisme fallback
vous permet de spécifier l’utilisation de plus d’un endpoint GraphQL, pour la même source.
Ceci est utile si vous voulez utiliser plus d’un Indexeur pour le même subgraph, et vous replier en cas d’erreur ou de dépassement de délai. Vous pouvez également utiliser cette stratégie pour utiliser un Indexeur personnalisé, mais lui permettre de se replier sur Le Service Hébergé de 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
`race`
Le mécanisme race
permet d’utiliser plusieurs endpoints GraphQL simultanément pour une même source et de prendre la réponse la plus rapide.
Cette option est utile si vous souhaitez utiliser plus d’un Indexeur pour le même subgraph, et permettre aux deux sources de faire la course et d’obtenir la réponse la plus rapide de tous les Indexeurs spécifiés.
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
`highestValue`
Cette stratégie vous permet d’envoyer des demandes parallèles à différents endpoints pour la même source et de choisir la plus récente.
Cette option est utile si vous souhaitez choisir les données les plus synchronisées pour le même subgraph parmi différents Indexeurs/sources.
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
Suivi des blocs
The Graph Client peut suivre les numéros de blocs et effectuer les requêtes suivantes en suivant ce schéma avec la transformation blockTracking
;
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 transforms:7 - blockTracking:8 # Vous pouvez désactiver la validation des schémas pour un démarrage plus rapide9 validateSchema: true10 # Ignorer les champs qui ne doivent pas être suivis11 ignoreFieldNames: [users, prices]12 # Exclure les opérations avec les noms suivants13 ignoreOperationNames: [NotFollowed]
Vous pouvez essayer un exemple pratique ici
Pagination automatique
Dans la plupart des subgraphs, le nombre d’enregistrements que vous pouvez récupérer est limité. Dans ce cas, vous devez envoyer plusieurs requêtes avec pagination.
1query {2 # Lance une erreur si la limite est de 10003 users(first: 2000) {4 id5 name6 }7}
Vous devez donc envoyer les opérations suivantes l’une après l’autre :
1query {2 # Lance une erreur si la limite est de 10003 users(first: 1000) {4 id5 name6 }7}
Ensuite, après la première réponse :
1query {2 # Lance une erreur si la limite est de 10003 users(first: 1000, skip: 1000) {4 id5 name6 }7}
Après la deuxième réponse, vous devez fusionner les résultats manuellement. En revanche, The Graph Client vous permet de faire la première réponse et exécute automatiquement ces demandes multiples pour vous.
Tout ce que vous avez à faire, c’est :
1sources:2 - name: uniswapv23 handler:4 graphql:5 endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v26 transforms:7 - autoPagination:8 # Vous pouvez désactiver la validation des schémas pour accélérer le démarrage.9 validateSchema: true
Vous pouvez essayer un exemple pratique ici
Composition côté client
The Graph Client est doté d’une prise en charge intégrée de la composition GraphQL côté client (assurée par GraphQL-Tools Schema-Stitching).
Vous pouvez tirer parti de cette fonctionnalité pour créer une seule couche GraphQL à partir de plusieurs subgraphs, déployés sur plusieurs Indexeurs.
💡 Astuce : Vous pouvez composer n’importe quelle source GraphQL, et pas seulement des subgraphs !
Une composition triviale peut être faite en ajoutant plus d’une source GraphQL à votre fichier .graphclientrc.yml
, voici un exemple :
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
Tant qu’il n’y a pas de conflit entre les schémas composés, vous pouvez les composer, puis exécuter une seule requête sur les deux subgraphs :
1query myQuery {2 # Celui-ci provient de compound-v23 markets(first: 7) {4 borrowRate5 }6 # Celui-ci provient de l'uniswap-v27 pair(id: "0x00004ee988665cdda9a1080d5792cecd16dc1220") {8 id9 token0 {10 id11 }12 token1 {13 id14 }15 }16}
Vous pouvez également résoudre des conflits, renommer des parties du schéma, ajouter des champs GraphQL personnalisés et modifier l’ensemble de la phase d’exécution.
Pour les cas d’utilisation avancée de la composition, veuillez vous référer aux ressources suivantes :
- Exemple de composition avancée
- Transformations de schémas GraphQL-Mesh
- Documentation GraphQL-Tools Schema-Stitching
Prise en charge de TypeScript
Si votre projet est écrit en TypeScript, vous pouvez exploiter la puissance de TypedDocumentNode
et avoir une expérience GraphQL client entièrement typée.
Le mode autonome de The GraphQL, et les bibliothèques client GraphQL populaires comme Apollo-Client et urql ont une prise en charge intégrée pour TypedDocumentNode
!
La CLI The Graph Client est livrée avec une configuration prête à l’emploi pour GraphQL Code Generator, et il peut générer TypedDocumentNode
sur la base de vos opérations GraphQL.
Pour commencer, définissez vos opérations GraphQL dans le code de votre application, et pointez vers ces fichiers en utilisant la section documents
de .graphclientrc.yml
:
1sources:2 - # ... vos sources Subgraphs/GQL ici34documents:5 - ./src/example-query.graphql
Vous pouvez également utiliser des expressions globales, ou même pointer vers des fichiers de code, et la CLI trouvera automatiquement vos requêtes GraphQL :
1documents:2 - './src/**/*.graphql'3 - './src/**/*.{ts,tsx,js,jsx}'
Maintenant, lancez à nouveau la commande build
de la CLI GraphQL, la CLI va générer un objet TypedDocumentNode
sous .graphclient
pour chaque opération trouvée.
Veillez à nommer vos opérations GraphQL, sinon elles seront ignorées !
Par exemple, une requête appelée query ExampleQuery
aura le ExampleQueryDocument
correspondant généré dans .graphclient
. Vous pouvez maintenant l’importer et l’utiliser pour vos appels GraphQL, et vous aurez une expérience entièrement typée sans écrire ou spécifier manuellement du TypeScript :
1import { ExampleQueryDocument, execute } from '../.graphclient'23async function main() {4 //La variable "result" est entièrement typée et représente la structure exacte des champs que vous avez sélectionnés dans votre requête.5 const result = await execute(ExampleQueryDocument, {})6 console.log(result)7}
Vous pouvez trouver un exemple de projet TypeScript ici.
Mutations côté client
En raison de la nature de la configuration de Graph-Client, il est possible d’ajouter un schéma côté client, que vous pouvez ensuite relier pour exécuter n’importe quel code arbitraire.
Cela est utile car vous pouvez implémenter du code personnalisé dans le cadre de votre schéma GraphQL et en faire un schéma d’application unifié qui est plus facile à suivre et à développer.
Ce document explique comment ajouter des mutations personnalisées, mais en fait vous pouvez ajouter n’importe quelle opération GraphQL (requête/mutation/abonnements). Voir Extension de l’article sur le schéma unifié pour plus d’informations sur cette fonctionnalité.
Pour commencer, définissez une section additionalTypeDefs
dans votre fichier de configuration :
1additionalTypeDefs: |2 # Nous devrions définir le type `Mutation` manquant3 extend schema {4 mutation: Mutation5 }67 type Mutation {8 doSomething(input: SomeCustomInput!): Boolean!9 }1011 input SomeCustomInput {12 field: String!13 }
Ensuite, ajoutez un pointeur vers un fichier de résolveurs GraphQL personnalisé :
1additionalResolvers:2 - './resolvers'
Maintenant, créez resolver.js
(ou, resolvers.ts
) dans votre projet, et implémentez votre mutation personnalisée :
1module.exports = {2 Mutation: {3 async doSomething(root, args, context, info) {4 // Ici, vous pouvez exécuter tout ce que vous voulez.5 // Par exemple, utiliser la librairie `web3`, connecter un portefeuille et ainsi de suite.67 return true8 },9 },10}
Si vous utilisez TypeScript, vous pouvez également obtenir une signature entièrement sécurisée en faisant :
1import { Resolvers } from './.graphclient'23// Maintenant, il est entièrement saisi !4const resolvers: Resolvers = {5 Mutation: {6 async doSomething(root, args, context, info) {7 // Ici, vous pouvez exécuter tout ce que vous voulez.8 // Par exemple, utiliser la librairie `web3`, connecter un portefeuille et ainsi de suite.910 return true11 },12 },13}1415export default resolvers
Si vous avez besoin d’injecter des variables d’exécution dans votre contexte
d’exécution GraphQL, vous pouvez utiliser l’extrait suivant :
1execute(2 MY_QUERY,3 {},4 {5 myHelper: {}, // Ceci sera disponible dans votre Mutation resolver as `context.myHelper`6 },7)
Licence
Publié sous la licence MIT.