Tiempo estimado: 6 minutos de lectura
En qué consisten las pruebas e integración de un subgrafo en una DApp
En mi anterior artículo sobre el indexado de datos de la blockchain comencé a explorar la creación y despliegue de un subgrafo con The Graph.
Las pruebas e integración de un subgrafo en una DApp sería el siguiente paso natural del proceso: consiste en validar las entidades y los mapeos del subgrafo como prerrequisito para integrar el endpoint del subgrafo en la DApp que consumirá los datos disponibles.
Pruebas del subgrafo
Una vez tenemos desplegado e indexado el subgrafo en Subgraph Studio, el entorno de pruebas en The Graph, podemos ejecutar las primeras consultas de forma muy sencilla a través del "playground".
Se trata de un entorno accesible desde el panel de control que permite fácilmente componer consultas en GraphQL para extraer en vivo datos del subgrafo.
GraphQL es un estándar de lenguaje y un entorno de ejecución de lado servidor para permitir a clientes (APIs) la obtención de conjuntos de datos complejos a través de un único endpoint.
En la siguiente imagen se aprecia un ejemplo de uso del playground:
Se ilustra la utilización del GraphiQL explorer, una interfaz que permite componer la consulta del cliente a partir de la selección de los elementos disponibles.
La consulta generada se puede utilizar directamente en los archivos de código fuente de la DApp para integrar el acceso a esos mismos datos.
Otra herramienta útil para probar y depurar un subgrafo sería el uso del logging API dentro del AssemblyScript API en The Graph. Permite registrar información de log dentro de los archivos de mapeo del subgrafo, usando varios niveles, para poder visualizarla desde Subgraph Studio o desde Graph Explorer.
Se ilustra con el siguiente fragmento de código
import { log } from "@graphprotocol/graph-ts";
const transferNumber = event.params.transferNumber;
const idBytes = bigIntTo32Bytes(transferNumber);
log.info('Adding new ChildTransfer event for ID: {} {}', [transferNumber.toString(), idBytes.toHexString()]);
let entity = new ChildTransfer(idBytes);
Integración del subgrafo en la DApp
Una vez se ha probado y depurado el subgrafo, se podría integrar el consumo de los datos indexados desde la DApp.
Con The Graph existen varias alternativas. Por su versatilidad y sencillez, se recoge a continuación el uso del graph-client, el cliente propio desarrollado en el proyecto The Graph. Existen sin embargo otras opciones como Apollo Client o URQL también fácilmente integrables.
El primer paso consiste en instalar la CLI del cliente como dependencia de desarrollo, para posteriormente generar los archivos necesarios de producción:
yarn add -D @graphprotocol/client-cli
Se debe crear un fichero ".graphclientrc.yml" en que se declare la URL del endpoint de desarrollo del subgrafo (se puede conseguir a través del portal en Subgraph Studio):
sources:
- name: my-subgraph
handler:
graphql:
endpoint: https://api.studio.thegraph.com/query/...
retry: 1
timeout: 5000
transforms:
- autoPagination:
validateSchema: false
limitOfRecords: 1000
A partir de aquí se invoca la CLI para crear de forma automática los artefactos que permitan interactuar con el subgrafo desde la DApp:
yarn graphclient build
Se crea la estructura de artefactos en el directorio ".graphclient".
Es importante reseñar que cada vez que se altere alguna configuración en el fichero ".graphclientrc.yml", se deben regenerar los artefactos.
Para consumir desde la DApp datos del subgrafo hay que importar la función "execute": método asíncrono que permite ejecutar consultas GraphQL suministrando los parámetros adecuados:
import { execute } from '.graphclient/index.js';
import { gql } from 'graphql-request'
const childTransferQuery = gql`
query MyQuery($parent: Bytes, $parentId: BigInt) {
childTransfers(where: {parent: $parent, parentId: $parentId}
orderBy: id,
orderDirection: desc
first: 3000)
{
id
status
timestamp
tokenId
}
}
`
let childTransfer = await execute(childTransferQuery,
{
parent: parent,
parentId: `${parentId}`
}
);
Opciones avanzadas del lado cliente
El cliente "graph-client" presenta algunas ventajas inherentes a su implementación. En general se configuran en el fichero ".graphclientrc.yml" (se pueden ver ejemplos en el suministrado como ejemplo anteriormente). Se destacan las dos siguientes:
- Estrategias de recuperación: se pueden definir los reintentos máximos en caso de error, el tiempo máximo de espera y el uso de varios endpoints en modo redundante.
- Autopaginación: el número máximo de resultados a recuperar en una consulta está limitado en The Graph a 1000. Para solventarlo se pueden paginar manualmente los resultados mediante "first/skip" o algún filtro (cursor filtering) o usar la función de autopaginación que lo gestiona de forma automática. Es importante reseñar que a pesar de todo, existe un límite máximo de 5000 resultados en una consulta autopaginada, teniendo que recurrir a paginación manual mediante filtrado si son necesarios más valores de retorno.
Indexado de datos off-chain
Otra de las utilidades que presenta un indexador es la posibilidad de mezclar datos generados fuera de la cadena (off-chain). The Graph en sus últimas actualizaciones provee el mecanismo de las fuentes de datos para acceder a datos off-chain de forma asíncrona, sin afectar el ritmo normal de indexación de los datos de la cadena.
Una de las fuentes de datos más habituales es IPFS, para cubrir entre otros el caso de uso típico de indexar cada NFT con sus metadatos.
Se esquematizan a continuación las definiciones básicas para este caso de uso:
#schema.graphql file
type ChildTransfer @entity(immutable: true) {
id: Bytes!
metaData: IpfsMetadata # 0 or 1 IpfsMetadata
tokenId: BigInt! # uint256
timestamp: BigInt! # uint256
status: BigInt! # uint256
}
type IpfsMetadata @entity(immutable: true) {
id: Bytes!
metaData: String!
}
#subgraph.yaml
templates:
- name: IpfsMetadata
kind: file/ipfs
mapping:
apiVersion: 0.0.9
language: wasm/assemblyscript
entities:
- IpfsMetadata
abis:
- name: MembershipManager
file: ./abis/MembershipManager.json
handler: handleIpfsContent
file: ./src/membership-manager.ts
# event handler in mappings file
// If the baseURI starts with "ipfs://", fetch metadata from IPFS
if(entity.baseURI.startsWith("ipfs://")) {
// Extract the CID from the baseURI
let hash = entity.baseURI.substring(7, entity.baseURI.length);
// Link the IpfsMetadata entity
entity.metaData = Bytes.fromUTF8(hash);
// Create a new dynamic data source for the IpfsMetadata template
IpfsMetadataTemplate.create(hash);
}
# file datasource handler in mapping file
export function handleIpfsContent(content: Bytes): void {
let hash = dataSource.stringParam();
log.warning('Handle metadata from: {}', [hash]);
// link the on-chain data with the off-chain retrieved content
let ipfs = new IpfsMetadata(Bytes.fromUTF8(hash));
ipfs.metaData = content.toString();
ipfs.save();
}
Conclusión: accediendo a datos estructurados de la blockchain desde las DApps
El consumo de datos estructurados de la blockchain desde una DApp es una tarea asequible y asumible mediante el uso de indexadores.
En este artículo se han presentado algunas claves que permiten poner a punto un subgrafo desplegado en The Graph mediante la herramienta Graph Studio.
Posteriormente el acceso a esos datos desde una aplicación descentralizada se puede conseguir mediante algunas de las librerías cliente disponibles para los desarrolladores.
La librería propia del proyecto The Graph se posiciona como una de las más versátiles y sencillas de utilizar, con algunas funciones avanzadas como la autopaginación para recuperar conjuntos amplios de resultados.
En el próximo artículo finalizaré el análisis de la plataforma The Graph tratando aspectos como las buenas prácticas en la construcción del subgrafo y su paso a producción en la red descentralizada.
¿Has utilizado alguna de las funciones avanzadas en The Graph para indexar los datos de tus smart contracts? ¿Mezclas datos de la cadena con información off-chain? ¡Comparte tus experiencias!
Si necesitas consumir datos estructurados desde tu DApp y no sabes cómo conseguir la información, puedo ayudarte a integrar un subgrafo en tu proyecto. Contáctame y analizamos juntos tu caso. ¡Un saludo!