API GraphQL
Reading time: 9 min
Este guia explica a API de Queries GraphQL usada para o Graph Protocol.
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") {idowner}}
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 {idowner}}
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) {idowner}}
Desde o Graph Node , 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) {idowner {name}}}
Atualmente, pode organizar por tipos String
or ID
de nível único em campos @entity
e @derivedFrom
. Infelizmente, , 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.
Consulte os 10 primeiros tokens:
{tokens(first: 10) {idowner}}
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.
Consulte 10 entidades Token
, deslocada por 10 posições do começo da coleção:
{tokens(first: 10, skip: 10) {idowner}}
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 }) {idowner}}
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
.
Faça um query sobre o challenges
com o resultado failed
:
{challenges(where: { outcome: "failed" }) {challengeroutcomeapplication {id}}}
Pode usar sufixos como _gt
, _lte
para comparar valores:
{applications(where: { deposit_gt: "10000000000" }) {idwhitelisteddeposit}}
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 } }) {idwhitelisteddeposit}}
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 } }) {challengeroutcomeapplication {id}}}
Desde o Graph Node , 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" }] }) {challengeroutcomeapplication {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" }) {challengeroutcomeapplication {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" }] }) {challengeroutcomeapplication {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.
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)
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. explica quais são estas limitações em detalhes.
{challenges(block: { number: 8000000 }) {challengeroutcomeapplication {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" }) {challengeroutcomeapplication {id}}}
Esta consulta retornará entidades Challenge
e as entidades Application
associadas, já que existiram diretamente após processar o bloco com o hash dado.
Campos de busca fulltext fornecem uma API de busca de texto expressiva, que pode ser adicionada e personalizada ao schema do subgraph. Refira ao 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ímbolo | Operador | Descrição |
---|---|---|
& | And | Para combinar múltiplos termos de busca num filtro para entidades que incluem todos os termos fornecidos |
| | Or | Consultas com vários termos de busca separados pelo operador or retornarão todas as entidades com uma correspondência de qualquer termo providenciado |
<-> | Follow by | Especifica a distância entre duas palavras. |
:* | Prefix | Use 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") {idtitlebodyauthor}}
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") {idtitlebodyauthor}}
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") {idtitlebodyauthor}}
O Graph Node implementa uma validação dos queries GraphQL que recebe usando o , que tem base na . Queries que não seguem uma regra de validação respondem com um erro padrão — visite a 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 .
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.
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 {numberhashtimestamp}deploymenthasIndexingErrors}}
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