Querying > API GraphQL

API GraphQL

Reading time: 10 min

This guide explains the GraphQL Query API that is used for The Graph Protocol.

Query

Collegamento a questa sezione

Nello schema di subgraph si definiscono tipi chiamati Entities. Per ogni tipo di Entity, un'entity e un campo entities saranno generati sul tipo Query di livello superiore. Si noti che query non deve essere inclusa all'inizio della query graphql quando si usa The Graph.

Eseguire query di una singola entità Token definita nello schema:

{
token(id: "1") {
id
owner
}
}

Nota: Quando si esegue una query per una singola entità, il campo id è obbligatorio e deve essere una stringa.

Eseguire query di tutte le entità Token:

{
tokens {
id
owner
}
}

Quando si esegue query di una collezione, il parametro orderBy può essere usato per ordinare in base a un attributo specifico. Inoltre, l'opzione orderDirection può essere usata per specificare la direzione dell'ordinamento, asc per l'ascendente oppure desc per il discendente.

{
tokens(orderBy: price, orderDirection: asc) {
id
owner
}
}

Esempio di ordinamento di entità annidate

Collegamento a questa sezione

A partire da Graph Node v0.30.0 le entità possono essere ordinate sulla base delle entità annidate.

Nell'esempio seguente, ordiniamo i token in base al nome del loro proprietario:

{
tokens(orderBy: owner__name, orderDirection: asc) {
id
owner {
name
}
}
}

Attualmente, è possibile ordinare per tipi di String oppure ID profondi un livello sui campi @entity e @derivedFrom. Purtroppo non è ancora supportato l'ordinamento per interfacce su entità profonde un livello, l'ordinamento per campi che sono array e entità annidate.

Quando si esegue una query di una collezione, il parametro first può essere usato per impaginare dall'inizio della raccolta. Va notato che l'ordinamento predefinito è per ID in ordine alfanumerico crescente, non per ora di creazione.

Inoltre, il parametro skip può essere usato per saltare le entità ed impaginare. Ad esempio, first:100 mostra le prime 100 entità e first:100, skip:100 mostra le 100 entità successive.

Le query dovrebbero evitare di usare valori skip molto grandi, perché in genere hanno un rendimento scarso. Per recuperare un gran numero di elementi, è molto meglio sfogliare le entità in base a un attributo, come mostrato nell'ultimo esempio.

Esempio di utilizzo di first

Collegamento a questa sezione

Eseguire query di primi 10 token:

{
tokens(first: 10) {
id
owner
}
}

Per eseguire query di gruppi di entità nel mezzo di una collezione, il parametro skip può essere usato insieme al parametro first per saltare un numero specifico di entità a partire dall'inizio della collezione.

Esempio di utilizzo di first e skip

Collegamento a questa sezione

Eseguire query di 10 entità Token, sfalsate di 10 posizioni rispetto all'inizio della collezione:

{
tokens(first: 10, skip: 10) {
id
owner
}
}

Esempio di utilizzo di first e id_ge

Collegamento a questa sezione

Se un client deve recuperare un gran numero di entità, è molto più performante basare le query su un attributo e filtrare in base a tale attributo. Ad esempio, un client potrebbe recuperare un gran numero di token utilizzando questa query:

query manyTokens($lastID: String) {
tokens(first: 1000, where: { id_gt: $lastID }) {
id
owner
}
}

La prima volta, si invierebbe la query con lastID = "" e per le richieste successive si imposterebbe lastID sull'attributo id dell'ultima entità della richiesta precedente. Questo approccio è nettamente migliore rispetto all'utilizzo di valori di skip crescenti.

È possibile utilizzare il parametro where nelle query per filtrare diverse proprietà. È possibile filtrare su più valori all'interno del parametro where.

Esempio di utilizzo di where

Collegamento a questa sezione

Query con esito failed:

{
challenges(where: { outcome: "failed" }) {
challenger
outcome
application {
id
}
}
}

È possibile utilizzare suffissi come _gt, _lte per confrontare i valori:

Esempio di filtraggio dell'intervallo

Collegamento a questa sezione
{
applications(where: { deposit_gt: "10000000000" }) {
id
whitelisted
deposit
}
}

Esempio di filtraggio dei blocchi

Collegamento a questa sezione

È anche possibile filtrare le entità in base al metodo _change_block(number_gte: Int) - questo filtra le entità che sono state aggiornate nel o dopo il blocco specificato.

Questo può essere utile se si vuole recuperare solo le entità che sono cambiate, ad esempio dall'ultima volta che è stato effettuato il polling. In alternativa, può essere utile per indagare o fare il debug di come le entità stanno cambiando nel subgraph (se combinato con un filtro di blocco, è possibile isolare solo le entità che sono cambiate in un blocco specifico).

{
applications(where: { _change_block: { number_gte: 100 } }) {
id
whitelisted
deposit
}
}

Esempio di filtraggio di entità annidate

Collegamento a questa sezione

Il filtraggio sulla base di entità annidate è possibile nei campi con il suffisso _.

Questo può essere utile se si vuole recuperare solo le entità il cui livello di figlio soddisfa le condizioni fornite.

{
challenges(where: { application_: { id: 1 } }) {
challenger
outcome
application {
id
}
}
}

A partire dalla versione Graph Node v0.30.0 è possibile raggruppare più parametri nello stesso argomento where usando gli operatori and oppure or per filtrare i risultati in base a più di un criterio.

Nell'esempio seguente, si filtrano le sfide con outcome succeeded e number maggiore o uguale a 100.

{
challenges(where: { and: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {
challenger
outcome
application {
id
}
}
}

Syntactic sugar: Si può semplificare la query precedente eliminando l'operatore and passando una sottoespressione separata da virgole.

{
challenges(where: { number_gte: 100, outcome: "succeeded" }) {
challenger
outcome
application {
id
}
}
}

Nell'esempio seguente, si filtrano le sfide con outcome succeeded oppure number maggiore o uguale a 100.

{
challenges(where: { or: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {
challenger
outcome
application {
id
}
}
}

Nota: Quando si costruiscono le query, è importante considerare l'impatto sulle prestazioni dell'uso dell'operatore or. Sebbene or possa essere uno strumento utile per ampliare i risultati della ricerca, può anche avere costi significativi. Uno dei problemi principali di or è che può causare un rallentamento delle query. Questo perché or richiede al database di eseguire la scansione di più indici, un processo che può richiedere molto tempo. Per evitare questi problemi, si consiglia agli sviluppatori di utilizzare gli operatori e al posto di o quando possibile. Ciò consente di effettuare filtri più precisi e di ottenere query più rapide e precise.

Elenco completo dei suffissi dei parametri:

_
_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

Si noti che alcuni suffissi sono supportati solo per tipi specifici. Ad esempio, Boolean supporta solo _not, _in e _not_in, mentre _ è disponibile solo per i tipi oggetto e interfaccia.

Inoltre, i seguenti filtri globali sono disponibili come parte dell'argomento where:

_change_block(number_gte: Int)

Query Time-travel

Collegamento a questa sezione

È possibile effetuare query dello stato delle entità non solo per l'ultimo blocco, che è quello predefinito, ma anche per un blocco nel passato. Il blocco in cui deve avvenire una query può essere specificato dal suo numero di blocco o dal suo hash, includendo un argomento block nei campi di livello superiore delle query.

Il risultato di una query di questo tipo non cambia nel tempo, cioè la query di un determinato blocco passato restituirà lo stesso risultato indipendentemente dal momento in cui viene eseguita, con l'eccezione che se si fa query di un blocco molto vicino alla testa della catena, il risultato potrebbe cambiare se quel blocco risulta non essere nella catena principale e la catena viene riorganizzata. Una volta che un blocco può essere considerato definitivo, il risultato della query non cambierà.

Si noti che l'attuale implementazione è ancora soggetta ad alcune limitazioni che potrebbero violare queste garanzie. L'implementazione non è sempre in grado di dire che un determinato block hash non è affatto presente nella chain principale, o che il risultato di una query per il block hash per un blocco che non può ancora essere considerato definitivo potrebbe essere influenzato da una riorganizzazione di blocco in corso contemporaneamente alla query. Non influiscono sui risultati delle query in base all'block hash quando il blocco è definitivo e si sa che si trova nella chain principale. Qui è spiegato in dettaglio quali sono queste limitazioni.

{
challenges(block: { number: 8000000 }) {
challenger
outcome
application {
id
}
}
}

Questa query restituirà le entità Challenge e le entità Application ad esse associate, così come esistevano direttamente dopo l'elaborazione del blocco numero 8.000.000.

{
challenges(block: { hash: "0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c" }) {
challenger
outcome
application {
id
}
}
}

Questa query restituirà le entità Challenge e le entità Application ad esse associate, così come esistevano direttamente dopo l'elaborazione del blocco con l'hash indicato.

Query di ricerca fulltext

Collegamento a questa sezione

I campi di ricerca fulltext forniscono un'API di ricerca testuale espressiva che può essere aggiunta allo schema del subgraph e personalizzata. Fare riferimento a Defining Fulltext Search Fields per aggiungere la ricerca fulltext al subgraph.

Le query di ricerca fulltext hanno un campo obbligatorio, text, per fornire i termini di ricerca. In questo campo di ricerca text sono disponibili diversi operatori speciali per il fulltext.

Operatori di ricerca fulltext:

SimboloOperatoreDescrizione
&AndPer combinare più termini di ricerca in un filtro per le entità che includono tutti i termini forniti
|OrLe query con più termini di ricerca separati dall'operatore Or restituiranno tutte le entità con una corrispondenza tra i termini forniti
<->Follow bySpecifica la distanza tra due parole.
:*PrefissoUtilizzare il termine di ricerca del prefisso per trovare le parole il cui prefisso corrisponde (sono richiesti 2 caratteri.)

Utilizzando l'operatore or, questa query filtrerà le entità blog con variazioni di "anarchism" o "crumpet" nei loro campi fulltext.

{
blogSearch(text: "anarchism | crumpets") {
id
title
body
author
}
}

L'operatore follow by specifica le parole a una distanza specifica nei documenti fulltext. La seguente query restituirà tutti i blog con variazioni di "decentralize" seguite da "philosophy"

{
blogSearch(text: "decentralized <-> philosophy") {
id
title
body
author
}
}

Combinare gli operatori fulltext per creare filtri più complessi. Con un operatore di ricerca pretext combinato con un follow by questa query di esempio corrisponderà a tutte le entità del blog con parole che iniziano con "lou" seguite da "music".

{
blogSearch(text: "lou:* <-> music") {
id
title
body
author
}
}

Graph Node implementa la validazione basata sulle specifiche delle query GraphQL che riceve utilizzando graphql-tools-rs, che si basa sull'implementazione di riferimento di graphql-js. Le query che non rispettano una regola di validazione vengono segnalate con un errore standard - per saperne di più, visitare le specifiche di GraphQL.

Lo schema dell'origine di dati-- cioè i tipi di entità, i valori e le relazioni disponibili per le query -- sono definiti attraverso GraphQL Interface Definition Langauge (IDL).

Gli schemi GraphQL in genere definiscono i tipi di radice per le query, le sottoscrizioni e le mutazioni. The Graph supporta solo le query. Il tipo di Query principale per il subgraph viene generato automaticamente dallo schema GraphQL incluso nel manifest del subgraph.

Nota: La nostra API non espone mutazioni perché gli sviluppatori devono emettere transazioni direttamente contro la blockchain sottostante dalle loro applicazioni.

Tutti i tipi GraphQL con direttive @entity nello schema saranno trattati come entità e devono avere un campo ID.

Nota: Attualmente, tutti i tipi nello schema devono avere una direttiva @entity. In futuro, i tipi senza direttiva @entity saranno trattati come oggetti valore, ma questo non è ancora supportato.

Metadati del Subgraph

Collegamento a questa sezione

Tutti i subgraph hanno un oggetto _Meta_ autogenerato, che fornisce accesso ai metadati del subgraph. Questo oggetto può essere interrogato come segue:

{
_meta(block: { number: 123987 }) {
block {
number
hash
timestamp
}
deployment
hasIndexingErrors
}
}

Se viene fornito un blocco, i metadati si riferiscono a quel blocco, altrimenti viene utilizzato il blocco indicizzato più recente. Se fornito, il blocco deve essere successivo al blocco iniziale del subgraph e inferiore o uguale al blocco indicizzato più recente.

deployment è un ID unico, corrispondente al CID IPFS del file subgraph.yaml.

block fornisce informazioni sull'ultimo blocco (tenendo conto di eventuali vincoli di blocco passati a _meta):

  • hash: l'hash del blocco
  • numero: il numero del blocco
  • timestamp: il timestamp del blocco, se disponibile (attualmente è disponibile solo per i subgraph che indicizzano le reti EVM)

hasIndexingErrors è un booleano che identifica se il subgraph ha incontrato errori di indicizzazione in qualche blocco passato

Modifica pagina

Precedente
Sistemi distribuiti
Successivo
Subgraph ID vs Deployment ID
Modifica pagina