Developer Superpowers with The Graph

So, we’ve been hearing a lot about The Graph lately. They’re getting a billion monthly queries, and as we all know, have experienced a few moments of downtime in the last few days. Ethereans are taking this as a good thing though, because it represents yet another piece of evidence that everything that we’re building is starting to get hit by unabated, massive waves of adoption.

So, you better be ready, because they’re gonna keep coming…

And coming…

No need to panic tho! The Graph’s got this. They’re on their way to decentralize the happy subgraphs that everyone’s building, so we should be able to scale and handle these surges in demand as it has been planned all along.

Now, just why does DeFi tremble when The Graph gets hit by these monster waves? Well, because everyone’s using The Graph, and it’s not decentralized yet. And why does everyone use The Graph? Well, because it’s just freakin’ awesome. Period. It’s like the italian mafia; Easy to get in, hard to get out. Once you try it, you realize how easy to use, and how powerful it is.

And how do you use it? Well, that’s what we’re going to talk about today.

GraphQL vs REST

Before we look into the usage, let’s quickly talk about what The Graph is, and what it builds upon. It’ll help us understand the general philosophy here.

The Graph is actually GraphQL, something that’s becoming ubiquitous in software in general. Twitter uses it, Github uses it, Facebook uses it, everyone uses it. It’s a replacement to the way front end clients, such as a web app, communicate with their back end. It use to be REST API calls, now it’s not.

With REST, our apps would interact with a bunch of endpoints that picked data off a database in the server. You’d have this endpoint for users, this other endpoint for locations, that endpoint for devices, and so on. Quite often, front end developers would have to get what they want by combining the data provided by two or more endpoints, and if this became a habit, someone would have to stop coding, get up, and have a little chat with the back end guys who happen to be on the path to the coffee machine.

“So, yeah. We’re gonna need that `users-3` endpoint to also contain hair color, but we don’t need nail length anymore.”

Back end engineers would hate front end engineers just a little more, and office life would continue as usual. With REST, some teams may even get fed up with this cyclical process, and one day, just go,

"Fuck it. Remove all the endpoints, just GIVE ME THE ENTIRE USER DATA ON A SINGLE ENDPOINT.”

Which would actually work, and the relationship between front and back end engineers would get a chance to heal, with the only caveat that they would all get fired because their app just became 100x slower and their servers caught fire on day 3 after the new release. Every single requests is fetching all the data, of which only a small percentage is used.

So, GraphQL fixes this. Not Bitcoin. GraphQL. GraphQL is that single endpoint, but it’s a dynamic endpoint; you can tell it exactly what you want it to pick off of the database. That single endpoint has access to all the data, and it can cherry pick just the data you need, and send only that over the network.

It’s like giving front and back end engineers the ability to communicate telepathically, and be friends again. And not get fired and all. All that they need to do, is speak the common tongue of “GraphQL queries”.

GraphQL Queries

This is what a query looks like:

query {
  pairs {
    token0 {
      symbol
    }
    token1 {
      symbol
    }
  }
}

That’s a UniswapV2 query, asking the all knowing oracle to list all the token pair symbols for you. Try it out yourself in The Graph explorer’s UniswapV2 subgraph.

Just paste the query on the left side of the playground (under “Example query”) and click the purple button. You should see JSON output like this:

{
  "token0": {
    "symbol": "OWL"
  },
  "token1": {
    "symbol": "WETH"
  }
},
{
  "token0": {
    "symbol": "NWC"
  },
  "token1": {
    "symbol": "WETH"
  }
},
...

Let’s break that query up:

query { // <---- Type of op. can be "query" or "subscription"
  pairs { // <-- Pair _object_
    token0 { <-- Pair.token0 Token _object_
      symbol <-- Token.symbol String _scalar_
    }
    token1 { <-- Pair.token1 Token _object_
      symbol <-- Token.symbol String _scalar_
    }
  }
}

Notice how there’s objects and scalars. Scalars are simple primitives like strings or numbers. Whenever you query an object, you need to use nested curlies and include at least another object or another scalar in them.

In a way, these queries are like a tree: objects are branches and scalars are leaves. You just need to make sure that you always end a branch with a leaf. The simplest form of a leaf is an id, which every object needs to have, and is simply a string that uniquely represents the object in the subgraph:

query {
  pairs {
    id <-- Pair.id ID (String) scalar
  }
}

Now, how do you know which objects a particular subgraph has? GraphQL is awesome here, because subgraphs are introspective, and thus self documented. On the right of the explorer we’ve used to make the query, you should be able to see the subgraph’s schema. Even if you aren’t entirely familiar with the syntax there, it should be enough to let you fool around making some pretty powerful queries.

You can now basically aswer any question you may have about UniswapV2 with this subgraph. And just take a look at all the available subgraphs hosted by The Graph’s explorer.

Are you beginning to feel the super power, or what?

Query Filters

Now, let’s take those queries to a whole new level with filters.

query {
  pairs(where: {
    volumeUSD_gt: 10000000
  }) {
    volumeUSD
    token0 {
      symbol
    }
    token1 {
      symbol
    }
  }
}

As you can see, where using parenthesis on the Pair object specifying a condition that we want met. In this case, we’re asking for UniswapV2’s markets with a volume of more that $10,000,000, and we get a bunch of token pairs back such as DAI/WETH, USDC/USDT, etc.

Making Queries from NodeJS

Of course, you’re going to want to make these queries from your app. Let’s see how this is done in a ultra minimalistic NodeJS project.

Just create a new directory, make it an npm project, install fetch, create a start.js file, and edit the file in your favorite editor, like so:

$ mkdir thegraph-test
$ cd thegraph-test
$ yarn init --yes
$ yarn add node-fetch
$ touch start.js
$ code .

In the start.js file, load the fetch api and take it for a spin by talking to our good ol’ friend Google:

const fetch = require('node-fetch')

async function main() {
  const res = await fetch('https://www.google.com')

  console.log(res)
}

main()

Now, run it, and you should see a healthy response object printed in the console.

$ node start.js

To use this to talk to a subgraph, you simply need to know where the subgraph is, and the rest is all about speaking query-lian.

If you go back to the UniswapV2 subgraph, you should see a “Queries (HTTP)” url just above the subgraph playground. Using this and a few tweaks in the fetch call, we arrive to this:

const fetch = require('node-fetch')

const SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2'

const query = `
query {
  pairs {
    id
  }
}
`

async function main() {
  const res = await fetch(SUBGRAPH_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ query })
  })

  const data = await res.json()
  console.log(JSON.stringify(data, null, 2))
}

main()

BOOM. That’s it.

You can now make powerful queries on practically any Ethereum protocol you want, and post-process the returned data with vanilla Javascript.

If you need to know more, check out The Graph’s super thorough documentation. Also, knowing that it’s GraphQL under the hood, there’s plenty of content in graphql.org.

I’ll be writing a post soon on how to create these subgraphs.

Enjoy your new superpower :D