API GraphQL
Reading time: 11 min
This guide explains the GraphQL Query API that is used for The Graph Protocol.
Dans votre schéma de subgraph, vous définissez des types appelés Entités
. Pour chaque type Entity
, un champ entity
et entities
sera généré sur le type Query
de niveau supérieur. Notez que query
n'a pas besoin d'être inclus en haut de la requête graphql
lors de l'utilisation de The Graph.
Requête pour une seule entité Token
définie dans votre schéma :
{token(id: "1") {idowner}}
Remarque : Lors d'une requête pour une seule entité, le champ id
est obligatoire et il doit s'agir d'une chaîne.
Interrogez toutes les entités Token
:
{tokens {idowner}}
Lors de l'interrogation d'une collection, le paramètre orderBy
peut être utilisé pour trier selon un attribut spécifique. De plus, orderDirection
peut être utilisé pour spécifier le sens du tri, asc
pour ascendant ou desc
pour décroissant.
{tokens(orderBy : price, orderDirection : asc) {idpropriétaire}}
Depuis Graph Node , les entités peuvent être triées sur la base d'entités imbriquées.
Dans l'exemple suivant, nous trions les jetons en fonction de leur nom propre:
{jetons (orderBy : propriétaire__nom, orderDirection : asc) {identifiantpropriétaire {{name}}}}
Actuellement, vous pouvez trier par types String
ou ID
profonds à un niveau sur les champs @entity
et @derivedFrom
. Malheureusement, le , le tri par champs qui sont des tableaux et des entités imbriquées est pas encore pris en charge.
Lors de l'interrogation d'une collection, le paramètre first
peut être utilisé pour paginer depuis le début de la collection. Il convient de noter que l'ordre de tri par défaut est par ID dans l'ordre alphanumérique croissant, et non par heure de création.
De plus, le paramètre skip
peut être utilisé pour ignorer des entités et paginer. par exemple. first:100
affiche les 100 premières entités et first:100, skip:100
affiche les 100 entités suivantes.
Les requêtes doivent éviter d'utiliser de très grandes valeurs de skip
car elles fonctionnent généralement mal. Pour récupérer un grand nombre d'éléments, il est préférable de parcourir les entités sur la base d'un attribut, comme le montre le dernier exemple.
Interroger les 10 premiers tokens :
{tokens(first: 10) {idowner}}
Pour rechercher des groupes d'entités au milieu d'une collection, le paramètre skip
peut être utilisé conjointement avec le paramètre first
pour ignorer un nombre spécifié d'entités en commençant par le début. de la collection.
Interrogez 10 entités Token
, décalées de 10 places depuis le début de la collection :
{tokens(first: 10, skip: 10) {idowner}}
Si un client a besoin de récupérer un grand nombre d'entités, il est beaucoup plus performant de baser les requêtes sur un attribut et de filtrer par cet attribut. Par exemple, un client récupérerait un grand nombre de jetons en utilisant cette requête :
query manyTokens($lastID: String) {tokens(first: 1000, where: { id_gt: $lastID }) {idowner}}
La première fois, il enverrait la requête avec lastID = ""
, et pour les requêtes suivantes, il définirait lastID
sur l'attribut id
du dernier entité dans la demande précédente. Cette approche fonctionnera nettement mieux que l'utilisation de valeurs skip
croissantes.
Vous pouvez utiliser le paramètre where
dans vos requêtes pour filtrer différentes propriétés. Vous pouvez filtrer sur plusieurs valeurs dans le paramètre where
.
Afficher les défis (Challenges) avec résultat failed
(échec) :
{challenges(where: { outcome: "failed" }) {challengeroutcomeapplication {id}}}
Vous pouvez utiliser des suffixes comme _gt
, _lte
pour comparer les valeurs :
{applications(where: { deposit_gt: "10000000000" }) {idwhitelisteddeposit}}
Vous pouvez également filtrer les entités par _change_block(number_gte: Int)
- cela filtre les entités qui ont été mises à jour dans ou après le bloc spécifié.
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 bien, il peut être utile d'étudier ou de déboguer la façon dont les entités changent dans votre subgraph (si combiné avec un filtre de bloc, vous pouvez isoler uniquement les entités qui ont changé dans un bloc spécifique).
{applications(where: { _change_block: { number_gte: 100 } }) {idwhitelisteddeposit}}
Un filtrage sur la base d'entités imbriquées est possible dans les champs portant 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.
{challenges(where: { application_: { id: 1 } }) {challengeroutcomeapplication {id}}}
Depuis Graph Node , vous pouvez regrouper plusieurs paramètres dans le même argument where
en utilisant les opérateurs et
ou ou
pour filtrer les résultats en fonction de plusieurs critères.
Dans l'exemple suivant, nous filtrons les défis (Challenges) dont le résultat et le numéro number
supérieur ou égal à 100
.
{challenges(where: { and: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {challengeroutcomeapplication {id}}}
Sucre syntaxique : Vous pouvez simplifier la requête ci-dessus en supprimant l'opérateur et
en passant une sous-expression séparée par des virgules.
{challenges(where: { number_gte: 100, outcome: "succeeded" }) {challengeroutcomeapplication {id}}}
Dans l'exemple suivant, nous filtrons les défis dont le résultat réussi (outcome
succeeded
) ou le numéro (number
) est supérieur ou égal à 100
.
{challenges(where: { or: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {challengeroutcomeapplication {id}}}
Remarque : lors de la création de requêtes, il est important de prendre en compte l'impact sur les performances de l'utilisation de l'opérateur ou
. Bien que ou
puisse être un outil utile pour élargir les résultats de recherche, il peut également avoir des coûts importants. L'un des principaux problèmes avec ou
est qu'il peut ralentir les requêtes. En effet, ou
nécessite que la base de données parcoure plusieurs index, ce qui peut prendre du temps. Pour éviter ces problèmes, il est recommandé aux développeurs d'utiliser les opérateurs et à la place de ou 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.
Liste complète des suffixes de paramètres :
__not_gt_lt_gte_lte_in_not_in_contains_contains_nocase_not_contains_not_contains_nocase_starts_with_starts_with_nocase_ends_with_ends_with_nocase_not_starts_with_not_starts_with_nocase_not_ends_with_not_ends_with_nocase
Veuillez noter que certains suffixes ne sont pris en charge que pour des types spécifiques. Par exemple, Boolean
ne prend en charge que _not
, _in
et _not_in
, mais _
est disponible uniquement pour les types d’objet et d’interface.
En outre, les filtres globaux suivants sont disponibles dans le cadre de l'argument where
:
_change_block(numéro_gte : Int)
Vous pouvez interroger l'état de vos entités non seulement pour le dernier bloc, qui est la valeur par défaut, mais également pour un bloc arbitraire du passé. Le bloc dans lequel une requête doit se produire peut être spécifié soit par son numéro de bloc, soit par son hachage 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 se trouvait 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.
Il convient de noter que l'implémentation actuelle est encore sujette à certaines limitations qui pourraient violer ces garanties. L'implémentation ne peut pas toujours dire qu'un bloc donné n'est pas du tout sur la chaîne principale, ou que le résultat d'une requête par bloc de hachage pour un bloc qui ne peut pas encore être considéré comme final peut être influencé par une réorganisation du bloc qui se déroule en même temps que la requête. Ils n'affectent pas les résultats des requêtes par hachage de bloc lorsque le bloc est final et que l'on sait qu'il se trouve sur la chaîne principale. explique ces limitations en détail.
{challenges(block: { number: 8000000 }) {challengeroutcomeapplication {id}}}
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.
{challenges(block: { hash: "0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c" }) {challengeroutcomeapplication {id}}}
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 hachage donné.
Les champs de requête de recherche en texte intégral fournissent une API de recherche textuelle expressive qui peut être ajoutée au schéma du subgraph et personnalisée. Reportez-vous à pour ajouter la recherche en texte intégral à votre subgraph.
Les champs de requête de recherche en texte intégral
, fournissent une Api de recherche de texte expressive qui peut être ajoutée au schéma de soubgraph et personnalisée. Reportez-vous à Définition des champs de recherche en texte intégral
pour ajouter une recherche en texte intégral à votre subgraph.
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.) |
En utilisant l'opérateur ou
, cette requête filtrera les entités de blog ayant des variations de "anarchism" ou "crumpet" dans leurs champs de texte intégral.
{blogSearch(text: "anarchism | crumpets") {idtitlebodyauthor}}
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 "décentraliser" suivies de "philosophie"
{blogSearch(text: "decentralized <-> philosophy") {idtitlebodyauthor}}
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 ».
{blogSearch(text: "lou:* <-> music") {idtitlebodyauthor}}
Graph Node met en œuvre une validation des requêtes GraphQL qu'il reçoit à l'aide de , qui est basée sur l'implémentation de référence . Les requêtes qui échouent à une règle de validation sont accompagnées d'une erreur standard - consultez la pour en savoir plus.
Le schéma de votre source de données, c'est-à-dire les types d'entités, les valeurs et les relations disponibles pour l'interrogation, est défini par le .
Les schémas GraphQL définissent généralement des types racine pour les requêtes
, les abonnements
et les mutations
. Le graphe 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 inclus dans le manifeste de votre subgraph.
Note: 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.
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
. À l'avenir, nous traiterons les types sans directive @entity
comme des objets de valeur, mais cela n'est pas encore possible.
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 :
{_meta(block: { number: 123987 }) {block {numberhashtimestamp}deploymenthasIndexingErrors}}
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 bloc indexé le plus récent.
deployment
est un identifiant unique, correspondant au CID IPFS du fichier subgraph.yaml
.
block
fournit des informations sur le dernier bloc (en tenant compte des contraintes de bloc transmises à _meta
) :
- hash : le hash du bloc
- number: the block number
- timestamp : l'horodatage du bloc, si disponible (ceci n'est actuellement disponible que pour les subgraphs indexant les réseaux EVM)
hasIndexingErrors
est un booléen identifiant si le subgraph a rencontré des erreurs d'indexation au cours d'un bloc passé