11 minutes
API GraphQL
Découvrez l’API de requête GraphQL utilisée dans The Graph.
Qu’est-ce que GraphQL ?
GraphQL est un langage d’interrogation pour les API et un moteur d’exécution pour l’exécution de ces requêtes avec vos données existantes. Le graphe utilise GraphQL pour interroger les subgraphs.
Pour comprendre le rôle plus important joué par GraphQL, consultez développer et créer un subgraph.
Requêtes avec GraphQL
Dans votre schéma Subgraph, vous définissez des types appelés Entities
. Pour chaque type Entity
, les champs entity
et entities
seront générés sur le type Query
de premier niveau.
Note : query
n’a pas besoin d’être inclus au début de la requête graphql
lors de l’utilisation de The Graph.
Exemples
Requête pour une seule entité Token
définie dans votre schéma :
1{2 token(id: "1") {3 id4 owner5 }6}
Note : Lors de l’interrogation d’une seule entité, le champ id
est obligatoire et doit être écrit sous forme de chaîne de caractères.
Interroge toutes les entités Token
:
1{2 tokens {3 id4 owner5 }6}
Tri
Lors de l’interrogation d’une collection, vous pouvez :
- Utilisez le paramètre
orderBy
pour trier les données en fonction d’un attribut spécifique. - Utilisez
orderDirection
pour spécifier la direction du tri,asc
pour ascendant oudesc
pour descendant.
Exemple
1{2 tokens(orderBy : price, orderDirection : asc) {3 id4 propriétaire5 }6}
Exemple de tri d’entités imbriquées
Depuis Graph Node v0.30.0
, les entités peuvent être triées sur la base des entités imbriquées.
L’exemple suivant montre des jetons triés par le nom de leur propriétaire :
1{2 jetons (orderBy : propriétaire__nom, orderDirection : asc) {3 identifiant4 propriétaire {5 {6 name7 }8 }9 }10}
Actuellement, vous pouvez trier par type String
ou ID
à “un” niveau de profondeur sur les champs @entity
et @derivedFrom
. Malheureusement, le [tri par interfaces sur des entités d’un niveau de profondeur] (https://github.com/graphprotocol/graph-node/pull/4058), le tri par champs qui sont des tableaux et des entités imbriquées n’est pas encore prit en charge.
Pagination
Lors de l’interrogation d’une collection, il est préférable de :
- Utilisez le paramètre
first
pour paginer à partir du début de la collection.- L’ordre de tri par défaut est le tri par
ID
dans l’ordre alphanumérique croissant, non par heure de création.
- L’ordre de tri par défaut est le tri par
- Utilisez le paramètre
skip
pour sauter des entités et paginer. Par exemple,first:100
affiche les 100 premières entités etfirst:100, skip:100
affiche les 100 entités suivantes. - Évitez d’utiliser les valeurs
skip
dans les requêtes car elles sont généralement peu performantes. Pour récupérer un grand nombre d’éléments, il est préférable de parcourir les entités en fonction d’un attribut, comme indiqué dans l’exemple précédent.
Exemple d’utilisation de first
Interroger les 10 premiers tokens :
1{2 tokens(first: 10) {3 id4 owner5 }6}
Pour rechercher des groupes d’entités au milieu d’une collection, le paramètre skip
peut être utilisé en conjonction avec le paramètre first
pour sauter un nombre spécifié d’entités en commençant par le début de la collection.
Exemple utilisant first
et skip
Interroger 10 entités Token
, décalées de 10 places par rapport au début de la collection :
1{2 tokens(first: 10, skip: 10) {3 id4 owner5 }6}
Exemple utilisant first
et id_ge
Si un client a besoin de récupérer un grand nombre d’entités, il est plus performant de baser les requêtes sur un attribut et de filtrer par cet attribut. Par exemple, un client pourrait récupérer un grand nombre de jetons en utilisant cette requête :
1query manyTokens($lastID: String) {2 tokens(first: 1000, where: { id_gt: $lastID }) {3 id4 owner5 }6}
La première fois, il enverra la requête avec lastID = ""
, et pour les requêtes suivantes, il fixera lastID
à l’attribut id
de la dernière entité dans la requête précédente. Cette approche est nettement plus performante que l’utilisation de valeurs skip
croissantes.
Filtration
- Vous pouvez utiliser le paramètre
where
dans vos requêtes pour filtrer les différentes propriétés. - Vous pouvez filtrer sur plusieurs valeurs dans le paramètre
where
.
Exemple d’utilisation de where
Défis de la requête avec un résultat failed
:
1{2 challenges(where: { outcome: "failed" }) {3 challenger4 outcome5 application {6 id7 }8 }9}
Vous pouvez utiliser des suffixes comme _gt
, _lte
pour comparer les valeurs :
Exemple de filtrage de plage
1{2 applications(where: { deposit_gt: "10000000000" }) {3 id4 whitelisted5 deposit6 }7}
Exemple de filtrage par bloc
Vous pouvez également filtrer les entités qui ont été mises à jour dans ou après un bloc spécifié avec _change_block(number_gte : Int)
.
Cela peut être utile si vous cherchez à récupérer uniquement les entités qui ont changé, par exemple depuis la dernière fois que vous avez interrogé. Ou encore, elle peut être utile pour étudier ou déboguer la façon dont les entités changent dans votre subgraph (si elle est combinée à un filtre de bloc, vous pouvez isoler uniquement les entités qui ont changé dans un bloc spécifique).
1{2 applications(where: { _change_block: { number_gte: 100 } }) {3 id4 whitelisted5 deposit6 }7}
Exemple de filtrage d’entités imbriquées
Le filtrage sur la base d’entités imbriquées est possible dans les champs avec le suffixe _
.
Cela peut être utile si vous souhaitez récupérer uniquement les entités dont les entités au niveau enfant remplissent les conditions fournies.
1{2 challenges(where: { application_: { id: 1 } }) {3 challenger4 outcome5 application {6 id7 }8 }9}
Opérateurs logiques
Depuis Graph Node v0.30.0
, vous pouvez regrouper plusieurs paramètres dans le même argument where
en utilisant les opérateurs and
ou or
pour filtrer les résultats en fonction de plusieurs critères.
L’opérateur AND
L’exemple suivant filtre les défis avec outcome
succeeded
et number
supérieur ou égal à 100
.
1{2 challenges(where: { and: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {3 challenger4 outcome5 application {6 id7 }8 }9}
Sucre syntaxique: Vous pouvez simplifier la requête ci-dessus en supprimant l’opérateur `and“ et en passant une sous-expression séparée par des virgules.
1{2 challenges(where: { number_gte: 100, outcome: "succeeded" }) {3 challenger4 outcome5 application {6 id7 }8 }9}
L’opérateur OR
L’exemple suivant filtre les défis avec outcome
succeeded
ou number
supérieur ou égal à 100
.
1{2 challenges(where: { or: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {3 challenger4 outcome5 application {6 id7 }8 }9}
Note : Lors de l’élaboration des requêtes, il est important de prendre en compte l’impact sur les performances de l’utilisation de l’opérateur or
. Si or
peut être un outil utile pour élargir les résultats d’une recherche, il peut aussi avoir des coûts importants. L’un des principaux problèmes de l’opérateur or
est qu’il peut ralentir les requêtes. En effet, or
oblige la base de données à parcourir plusieurs index, ce qui peut prendre beaucoup de temps. Pour éviter ces problèmes, il est recommandé aux développeurs d’utiliser les opérateurs and au lieu de or chaque fois que cela est possible. Cela permet un filtrage plus précis et peut conduire à des requêtes plus rapides et plus précises.
Tous les filtres
Liste complète des suffixes de paramètres :
1_2_not3_gt4_lt5_gte6_lte7_in8_not_in9_contains10_contains_nocase11_not_contains12_not_contains_nocase13_starts_with14_starts_with_nocase15_ends_with16_ends_with_nocase17_not_starts_with18_not_starts_with_nocase19_not_ends_with20_not_ends_with_nocase
Veuillez noter que certains suffixes ne sont supportés que pour des types spécifiques. Par exemple, Boolean
ne supporte que _not
, _in
, et _not_in
, mais _
n’est disponible que pour les types objet et interface.
En outre, les filtres globaux suivants sont disponibles en tant que partie de l’argument where
:
1_change_block(numéro_gte : Int)
Interrogation des états précédents
Vous pouvez interroger l’état de vos entités non seulement pour le dernier bloc, ce qui est le cas par défaut, mais aussi pour un bloc arbitraire dans le passé. Le bloc auquel une requête doit se produire peut être spécifié soit par son numéro de bloc, soit par son hash de bloc, en incluant un argument block
dans les champs de niveau supérieur des requêtes.
Le résultat d’une telle requête ne changera pas au fil du temps, c’est-à-dire qu’une requête portant sur un certain bloc passé renverra le même résultat quel que soit le moment où elle est exécutée, à l’exception d’une requête portant sur un bloc très proche de la tête de la chaîne, dont le résultat pourrait changer s’il s’avérait que ce bloc ne figurait pas sur la chaîne principale et que la chaîne était réorganisée. Une fois qu’un bloc peut être considéré comme définitif, le résultat de la requête ne changera pas.
Remarque : l’implémentation actuelle est encore sujette à certaines limitations qui pourraient violer ces garanties. L’implémentation ne permet pas toujours de déterminer si un bloc donné n’est pas du tout sur la chaîne principale ou si le résultat d’une requête par bloc pour un bloc qui n’est pas encore considéré comme final peut être influencé par une réorganisation du bloc qui a lieu en même temps que la requête. Elles n’affectent pas les résultats des requêtes par hash de bloc lorsque le bloc est final et que l’on sait qu’il se trouve sur la chaîne principale. Ce numéro explique ces limitations en détail.
Exemple
1{2 challenges(block: { number: 8000000 }) {3 challenger4 outcome5 application {6 id7 }8 }9}
Cette requête renverra les entités Challenge
et les entités Application
qui leur sont associées, telles qu’elles existaient directement après le traitement du bloc numéro 8 000 000.
Exemple
1{2 challenges(block: { hash: "0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c" }) {3 challenger4 outcome5 application {6 id7 }8 }9}
Cette requête renverra les entités Challenge
, et leurs entités Application
associées, telles qu’elles existaient directement après le traitement du bloc avec le hash donné.
Requêtes de recherche en texte intégral
Les champs de recherche intégralement en texte fournissent une API de recherche textuelle expressive qui peut être ajoutée au schéma du subgraph et personnalisée. Reportez-vous à Définir des champs de recherche en texte intégral pour ajouter la recherche intégralement en texte à votre subgraph.
Les requêtes de recherche en texte intégral comportent un champ obligatoire, text
, pour fournir les termes de la recherche. Plusieurs opérateurs spéciaux de texte intégral peuvent être utilisés dans ce champ de recherche text
.
Opérateurs de recherche en texte intégral :
Symbole | Opérateur | Description |
---|---|---|
& | And | Pour combiner plusieurs termes de recherche dans un filtre pour les entités incluant tous les termes fournis |
| | Or | Les requêtes comportant plusieurs termes de recherche séparés par l’opérateur ou renverront toutes les entités correspondant à l’un des termes fournis |
<-> | Follow by | Spécifiez la distance entre deux mots. |
:* | Prefix | Utilisez le terme de recherche de préfixe pour trouver les mots dont le préfixe correspond (2 caractères requis.) |
Exemples
En utilisant l’opérateur ou
, cette requête filtrera les entités de blog ayant des variations d’ “anarchism” ou “crumpet” dans leurs champs de texte intégral.
1{2 blogSearch(text: "anarchism | crumpets") {3 id4 title5 body6 author7 }8}
L’opérateur follow by
spécifie un mot à une distance spécifique dans les documents en texte intégral. La requête suivante renverra tous les blogs contenant des variations de “decentralize” suivies de “philosophy”
1{2 blogSearch(text: "decentralized <-> philosophy") {3 id4 title5 body6 author7 }8}
Combinez des opérateurs de texte intégral pour créer des filtres plus complexes. Avec un opérateur de recherche de prétexte combiné à un suivi de cet exemple, la requête fera correspondre toutes les entités de blog avec des mots commençant par « lou » suivi de « musique ».
1{2 blogSearch(text: "lou:* <-> music") {3 id4 title5 body6 author7 }8}
Validation
Graph Node met en œuvre une validation basée sur les spécifications des requêtes GraphQL qu’il reçoit à l’aide de graphql-tools-rs, qui est basée sur l’implémentation de référence graphql-js. Les requêtes qui échouent à une règle de validation sont accompagnées d’une erreur standard - consultez les spécifications GraphQL pour en savoir plus.
Schema
Le schéma de vos sources de données, c’est-à-dire les types d’entités, les valeurs et les relations qui peuvent être interrogés, est défini dans le GraphQL Interface Definition Language (IDL).
Les schémas GraphQL définissent généralement des types racines pour les queries
, les subscriptions
et les mutations
. The Graph ne prend en charge que les requêtes
. Le type racine Query
pour votre subgraph est automatiquement généré à partir du schéma GraphQL qui est inclus dans votre Subgraph manifest.
Remarque : notre API n’expose pas les mutations car les développeurs sont censés émettre des transactions directement contre la blockchain sous-jacente à partir de leurs applications.
Entities
Tous les types GraphQL avec des directives @entity
dans votre schéma seront traités comme des entités et doivent avoir un champ ID
.
Note: Actuellement, tous les types de votre schéma doivent avoir une directive @entity
. Dans le futur, nous traiterons les types n’ayant pas la directive @entity
comme des objets de valeur, mais cela n’est pas encore pris en charge.
Métadonnées du Subgraph
Tous les subgraphs ont un objet _Meta_
auto-généré, qui permet d’accéder aux métadonnées du subgraph. Cet objet peut être interrogé comme suit :
1{2 _meta(block: { number: 123987 }) {3 block {4 number5 hash6 timestamp7 }8 deployment9 hasIndexingErrors10 }11}
Si un bloc est fourni, les métadonnées sont celles de ce bloc, sinon le dernier bloc indexé est utilisé. S’il est fourni, le bloc doit être postérieur au bloc de départ du subgraph et inférieur ou égal au dernier bloc indexé.
deployment
est un ID unique, correspondant au IPFS CID du fichier subgraph.yaml
.
block
fournit des informations sur le dernier bloc (en tenant compte des contraintes de bloc passées à _meta
) :
- hash : le hash du bloc
- number: the block number
- horodatage : l’horodatage du bloc, s’il est disponible (pour l’instant, cette information n’est disponible que pour les subgraphs indexant les réseaux EVM)
hasIndexingErrors
est un booléen indiquant si le subgraph a rencontré des erreurs d’indexation à un moment donné