Episode 39 integrates GraphQL with blockchain and Web3: The Graph Protocol for indexing on-chain data, subgraph development with subgraph.yaml, smart contract integration with ethers.js, querying NFT metadata with OpenSea and IPFS, and DeFi applications.

Blockchain is an unusual data store: transparent, immutable, but hard to query directly. Episode 39 connects GraphQL with the Web3 world — through The Graph Protocol and smart contract integration.
We'll learn about The Graph and subgraph development, smart contract integration with ethers.js, querying NFT metadata, and DeFi application examples.
The Graph Protocol is a decentralized network for indexing blockchain data. The network runs subgraphs — indexing definitions that determine which events to monitor and how the data is served — then exposes them as GraphQL endpoints.
Its advantage: on-chain data that's hard to query directly (events and logs) can be indexed into a fast GraphQL API. Many DeFi and NFT apps are built on subgraphs.
npx graph init --studio protocol-xyz/mysubgraphA subgraph consists of subgraph.yaml (configuration), schema.graphql (the GraphQL schema), and mapping handlers:
specVersion: 1.0.0
schema:
file: ./schema.graphql
dataSources:
- kind: ethereum/contract
name: TransferContract
network: mainnet
source:
address: "0x..."
abi: TransferContract
mapping:
kind: ethereum/events
language: wasm/assemblyscript
entities:
- Transfer
eventHandlers:
- event: Transfer(address,address,uint256)
handler: handleTransfertype Transfer @entity {
id: ID!
from: Bytes!
to: Bytes!
amount: BigInt!
}Once deployed, the subgraph endpoint can be queried like ordinary GraphQL:
query Transfers {
transfers(first: 10) {
from
to
amount
}
}Subgraphs handle the on-chain query needs: balance history, transfers, token ownership, and aggregate data — things that are impossible to do directly in a smart contract.
For direct integration with smart contracts in your own apps, use ethers.js; install with npm install ethers:
import { ethers } from "ethers";
async function tokenBalance(_, args, ctx) {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const contract = new ethers.Contract(
args.contractAddress,
["function balanceOf(address) view returns (uint256)"],
provider
);
const balance = await contract.balanceOf(args.owner);
return balance.toString();
}Wallet authentication uses cryptographic signatures: the client asks the server to send a message (challenge), the client signs it with their wallet, and the server verifies — this proves wallet ownership without a password. For transaction monitoring, combine: GraphQL subscriptions for events from the subgraph, and ethers.js to monitor transaction status directly when needed.
NFT data is spread out: ownership on-chain, metadata on IPFS. The common patterns:
async function nftMetadata(_, args, ctx) {
const uri = `https://ipfs.io/ipfs/${args.cid}`;
const res = await fetch(uri);
return res.json();
}Real-time NFT updates (new listings, offers, sales) are handled with subscriptions on the subgraph or marketplace webhooks.
DeFi apps depend heavily on real-time data:
query PoolInfo {
liquidityPool(id: "0x...") {
token0 { symbol price }
token1 { symbol price }
totalLiquidity
}
}Multi-chain support: deploy a subgraph per chain or use a cross-chain indexer; keep one GraphQL endpoint in front for abstraction. Combine with caching (episode 20) because prices change quickly while other on-chain data can be cached longer.
Key takeaways:
In the next episode, episode 40, you'll learn about spec updates and the future of GraphQL — specification evolution, the @defer and @stream directives for incremental delivery, upcoming features like Client Controlled Nullability and Fragment Arguments, and the GraphQL Foundation community. You'll know where this technology is headed!