Querying > API GraphQL

API GraphQL

Reading time: 9 min

Este guia explica a API de Queries GraphQL usada para o Graph Protocol.

Queries (Consultas em query)

Link para esta seção

No schema do seu subgraph, são definidos tipos chamados de Entities (Entidade). Para cada tipo de Entity, um campo de entity e entities será gerado no tipo Query de alto nível. Note que o query não precisa ser incluído no topo da consulta graphql ao usar o The Graph.

Um query para uma única entidade Token definida no seu schema:

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

Nota: Ao fazer um query para uma única entidade, é obrigatório um campo id; este deve ser um string.

Consulte todas as entidades Token:

{
tokens {
id
owner
}
}

Organização

Link para esta seção

Ao consultar uma coleção, o parâmetro orderBy pode ser usado para organizar por um atributo específico. Além disto, o orderDirection serve para especificar a direção de organização, sendo asc para ascendente ou desc para descendente.

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

Exemplo para organização de entidade aninhada

Link para esta seção

Desde o Graph Node v0.30.0, as entidades podem ser organizadas com base nas entidades aninhadas.

No seguinte exemplo, organizamos os tokens pelo nome do dono:

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

Atualmente, pode organizar por tipos String or ID de nível único em campos @entity e @derivedFrom. Infelizmente, a organização por interfaces em entidades de nível único, que é a organização por campos que são arranjos e entidades aninhadas, ainda não tem apoio.

Ao consultar uma coleção, o parâmetro first (primeiro) serve para paginar do começo da coleção. Vale notar que a ordem de organização padrão é por ID em ordem alfanumérica ascendente, não por hora de criação.

E mais: o parâmetro skip serve para pular entidades e paginar. Por ex. first:100 mostra as primeiras 100 entidades e first:100, skip:100 mostra as próximas 100.

Evite usar valores skip muito grandes nos queries, pois estes tendem a ter um mau desempenho. Para resgatar um grande número de itens, é muito melhor paginar por entidades com base num atributo, como visto no último exemplo.

Exemplo com o first

Link para esta seção

Consulte os 10 primeiros tokens:

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

Para queries sobre grupos de entidades no meio de uma coleção, o parâmetro skip serve em conjunto com o parâmetro first para pular um número especificado de entidades, a começar no início da coleção.

Exemplo com first e skip

Link para esta seção

Consulte 10 entidades Token, deslocada por 10 posições do começo da coleção:

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

Exemplo com first e id_ge

Link para esta seção

Se um cliente precisar retirar um grande número de entidades, é muito mais eficiente basear consultas num atributo e filtrar pelo mesmo. Por exemplo, um cliente retiraria um número grande de tokens com este query:

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

Na primeira vez, ele enviaria a consulta com lastID = "", e em pedidos seguintes, configuraria lastID no atributo id da última entidade no pedido anterior. Este método será mais eficiente do que usar valores skip crescentes.

O parâmetro where serve nas suas consultas para filtrar por propriedades diferentes. É possível filtrar em múltiplos valores dentro do parâmetro where.

Exemplo com where

Link para esta seção

Faça um query sobre o challenges com o resultado failed:

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

Pode usar sufixos como _gt, _lte para comparar valores:

Exemplo para filtragem de alcance

Link para esta seção
{
applications(where: { deposit_gt: "10000000000" }) {
id
whitelisted
deposit
}
}

Exemplo para filtragem de blocos

Link para esta seção

Também dá para filtrar entidades pelo _change_block(number_gte: Int) — o que filtra entidades atualizadas no bloco especificado ou depois dele.

Isto pode servir caso mire retirar apenas entidades que mudaram, por exemplo, desde a última vez que você pesquisou. Também pode ser bom investigar ou debugar como as entidades mudam no seu subgraph (se combinado com um filtro de blocos, pode isolar apenas entidades que mudaram em um bloco específico).

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

Exemplo para filtragem de entidade ninhada

Link para esta seção

A filtragem na base de entidades ninhadas é possível nos campos com o sufixo _.

Isto é bom caso mire retirar apenas entidades cujas entidades de nível-filho correspondem às condições requeridas.

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

Operadores lógicos

Link para esta seção

Desde o Graph Node v0.30.0, pode agrupar vários parâmetros no mesmo argumento where com operadores and ou or, para filtrar resultados com base em mais de um critério.

No seguinte exemplo, filtramos por desafios com outcome, succeeded e number maiores que ou iguais a 100.

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

Açúcar sintático: pode simplificar a consulta acima ao retirar o operador and, com o passe de uma subexpressão separada por vírgulas.

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

No seguinte exemplo, filtramos por desafios com outcome, succeeded e number maiores que ou iguais a 100.

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

Nota: Ao construir consultas, é importante considerar o impacto do desempenho do operador or. Enquanto o or pode ser útil para ampliar os resultados da busca, ele também pode ter custos significativos. Um dos maiores problemas com o or é que pode reduzir a velocidade das consultas. Isto é porque o or exige que o banco de dados escaneie por vários indexes, o que pode demorar muito. Para evitar estes problemas, recomendamos que os programadores usem operadores and em vez de or sempre que possível. Isto retorna filtragens mais precisas, e pode levar a consultas mais rápidas e confiáveis.

Todos os Filtros

Link para esta seção

Lista completa de sufixos de parâmetro:

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

Perceba que alguns sufixos só tem apoio para tipos específicos. Por exemplo, o Boolean só apoia _not, _in, e _not_in, mas o _ só está disponível para tipos de objeto e interface.

Além disto, os seguintes filtros globais estão disponíveis como parte do argumento where:

_change_block(number_gte: Int)

Consultas de viagem no tempo

Link para esta seção

Pode consultar o estado das suas entidades não só para o bloco mais recente, que é o padrão, mas também para um bloco arbitrário no passado. O bloco em que acontece um query pode ser especificado pelo seu número, ou pelo seu hash, ao incluir um argumento block nos campos de nível alto de query.

O resultado de um tal query não mudará com o tempo; por ex., queries num certo bloco passado retornarão o mesmo resultado, independente de quando ele for executado. Exceto que, se fizer um query num bloco muito perto do topo da chain, o resultado pode mudar se aquele bloco acabar ausente da chain principal e a chain for reorganizada. Quando um bloco puder ser considerado final, o resultado da consulta não mudará.

Note que a implementação atual ainda é sujeita a certas limitações que podem violar estas garantias. A implementação nem sempre percebe que um hash de bloco não está na chain principal, ou que uma consulta por hash de bloco retorna um bloco que não pode ser considerado final, mas que pode ser influenciado por uma reorganização de bloco executada concorrente com a consulta. Este inquérito explica quais são estas limitações em detalhes.

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

Esta consulta retornará entidades Challenge e as entidades Application associadas, já que existiram diretamente após processar o bloco de número 8.000.000.

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

Esta consulta retornará entidades Challenge e as entidades Application associadas, já que existiram diretamente após processar o bloco com o hash dado.

Consultas de Busca Fulltext

Link para esta seção

Campos de busca fulltext fornecem uma API de busca de texto expressiva, que pode ser adicionada e personalizada ao schema do subgraph. Refira ao Definindo Campos de Busca Fulltext para adicionar buscas fulltext ao seu subgraph.

Buscas fulltext têm um campo obrigatório, text, para ofertar termos de busca. Vários operadores especiais de fulltext estão disponíveis para uso neste campo de busca text.

Operadores de busca fulltext:

SímboloOperadorDescrição
&AndPara combinar múltiplos termos de busca num filtro para entidades que incluem todos os termos fornecidos
|OrConsultas com vários termos de busca separados pelo operador or retornarão todas as entidades com uma correspondência de qualquer termo providenciado
<->Follow byEspecifica a distância entre duas palavras.
:*PrefixUse o prefixo para encontrar palavras que correspondem a tal prefixo (2 caracteres necessários.)

Ao usar o operador or, esta consulta filtrará para entidades com variações de "anarchism" ou "crumpet" nos seus campos fulltext.

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

O operador follow by especifica palavras separadas por uma distância específica nos documentos fulltext. A seguinte consulta retornará todos os blogs com variações de "decentralize" ("descentralizar") seguido por "philosophy" ("filosofia")

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

Combine operadores de fulltext para fazer filtros mais complexos. Com um operador de busca pretext combinado com um 'follow by', este exemplo de consulta corresponderá todas as entidades de blog com palavras que começam com "lou" seguido de "music".

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

O Graph Node implementa uma validação baseada em especificação dos queries GraphQL que recebe usando o graphql-tools-rs, que tem base na implementação de referência do graphql-js. Queries que não seguem uma regra de validação respondem com um erro padrão — visite a spec do GraphQL para saber mais.

O schema da sua fonte de dados — isto é, os tipos de entidade, valores e relacionamentos disponíveis à consulta — são definidos através da Linguagem de Definição de Interface GraphQL (IDL).

Os schemas GraphQL geralmente definem tipos de raiz para queries (consultas), subscriptions (inscrições) e mutations (mutações). O The Graph só apoia queries. O tipo raiz Query para o seu subgraph é gerado automaticamente a partir do schema GraphQL incluído no manifest do seu subgraph.

Nota: A nossa API não expõe mutações, porque se espera que programadores emitam transações diretamente perante a blockchain subjacente, a partir dos seus aplicativos.

Todos os tipos GraphQL com diretivos @entity no seu schema serão tratados como entidades, e devem ter um campo ID.

Nota: Atualmente, todos os tipos no seu schema devem ter um diretivo @entity. No futuro, trataremos tipos sem um diretivo @entity como objetos de valor, mas ainda não há apoio a isto.

Metadados de Subgraph

Link para esta seção

Todos os subgraphs devem ter um objeto _Meta_ gerado automaticamente, que permite acesso aos metadados do subgraph. Isto pode ser consultado num query como o seguinte:

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

Se um bloco for fornecido, os metadados são desde aquele bloco; e se não, é usado o último indexado. Se providenciado, o bloco deve ser após o inicial do subgraph, e menor ou igual ao bloco indexado mais recentemente.

deployment é uma ID única, correspondente ao CID PIFS do arquivo subgraph.yaml.

O block fornece informações sobre o bloco mais recente (em consideração a quaisquer limites de bloco passados ao _meta):

  • hash: o hash do bloco
  • number: o número do bloco
  • timestamp: a hora do bloco, se disponível (disponível atualmente apenas para subgraphs que indexam redes EVM)

hasIndexingErrors é um boolean que identifica se o subgraph encontrou erros de indexação em algum bloco passado

Editar página

Anterior
Sistemas Distribuídos
Próximo
ID de Subgraph contra ID de Lançamento
Editar página