Deserialize YAML
Prerequisites
We're also using Microsoft Visual Studio Code as a text editor. Here are the installation instructions for a variety of popular operating systems.
Overview
In this lesson we’re building a program to deserialize a generic subgraph manifest. Before we go any further, let's get on the same page about deserialization and subgraph manifests.
Deserialization
Deserialization: The process whereby a lower-level format (e.g. that has been transferred over a network, or stored in a data store) is translated into a readable object or other data structure.
Subgraph manifests
The subgraph manifest
subgraph.yaml
defines the smart contracts your subgraph indexes, which events from these contracts to pay attention to, and how to map event data to entities that Graph Node stores and allows to query.
For the full subgraph manifest specification visit this link, but here's an abbreviated, list-based tour of subgraph manifest fields, subfields, and their types (in no particular order):
specVersion
: A Semver version indicating which version of this API is being used.String
type
repository
: An optional link to where the subgraph lives.String
type
description
: An optional description of the subgraph’s purposeString
type
dataSources
: Each data source spec defines the data that will be ingested as well as the transformation logic to derive the state of the subgraph’s entities based on the source data.Data Source Spec
typeSubfields type
kind
: The type of data source. Possible values: ethereum/contract.String
type
name
: The name of the source data. Will be used to generate APIs in the mapping and also for self-documentation purposes.String
type
network
: For blockchains, this describes which network the subgraph targets. Developers can look for an up to date list in the graph-cli.String
type
source
: The source data on a blockchain such as Ethereum.mapping
: The transformation logic applied to the data prior to being indexed.Mapping
type
Rust code
Along with previously covered Rust concepts (see other guides), here’s a quick overview of the topics we’ll encouter in this lesson
define custom
structs
that represent the generic properties of a subgraph manifestleverage
serde_yaml
crate andserde
crate’sderive
macro to deserialize the subgraph manifestYAML
into customstructs
.validate a program with a basic test
Open your terminal/command line, create a new
cargo
project, then open it with VSCode
Click
Cargo.toml
in the VSCode Explorer then modify the file with the following dependencies (add the following code below[dependencies]
) then save your changes
reqwest
“provides a convenient, higher-level HTTP Client”tokio
is an “event-driven, non-blocking I/O platform for writing asynchronous applications with the Rust programming language”serde
is a “framework for serializing and deserializing Rust data structures efficiently and generically”serde_yaml
is a library for using the Serde serialization framework with data in YAML file format.
Right click the
src
directory in the VSCode Explorer then select "New file..." and create a file calledutils.rs
. Add the following code to the newly created file.
std::collections::HashMap
- A hash map implemented with quadratic probing and SIMD lookup.std::string::String
- A UTF-8–encoded, growable string.serde::Deserialize
- A data structure that can be deserialized from any data format supported by Serde.
Next, add some
struct
statements to the same file then save
Description of structs
SubgraphManifest
- maps to a subgraph manifest and some of it’s fieldsSchemaAddress
- `maps to a manifest’s schema address on IPFSDataSource
- maps to a single entry in a manifest’sdataSources
Mapping
- maps tomapping
field of adataSource
entrySource
- maps tosource
field of adataSource
entry
See Subgraph Manifest docs for full specification details.
Click on
src/main.rs
in the VSCode Explorer to open the file. Delete all the existing file contents then add the followinguse
andmod
statements to the file.
use std::error::Error
- a trait representing the basic expectations for error values, i.e., values of typeE
inResult<T, E>
.mod utils
- will look for a file namedutils.rs
and will insert its contents inside a module namedutils
under this scopeuse crate::utils::SubgraphManifest
- will bind fullcrate::utils::SubgraphManifest
path toSubgraphManifest
for easier access
Now add a
main
function with the following content below theuse
andmod
statements
Some notes:
our
main
function isasync
, powered bytokio
doesn’t return a value so we use the
unit
type in our resultalso note the
unit
type inOk(())
Boxing errors from our result with
Box<dyn Error>
we perform a
GET
request toIPFS
then store response text inmanifest_response
variablewe leverage
serde_yaml
to deserialize a reference tomanifest_response
into a variablemanifest_data
of typeSubgraphManifest
finally we print out
manifest_data
to our terminal
Save your changes then run the program from the integrated terminal in VSCode
To wrap things up let’s add a test below the
main
function. Check out Chapter 11 of The Rust Programming Language book for a more thorough discussion of tests in Rust. We’re leveragingtokio
again to help with ourasync
testing.
Instead of printing results to our terminal, we use assert_eq
macro to compare the deserialized manifest repository URL with a hard-coded value we provide. Additionally we are testing against the Everest
subgraph in this function.
Go ahead and run your test.
Last updated