# Query a Subgraph

Source: https://docs.graphops.xyz/subgraphs/guides/query-a-subgraph

Read indexed entities from your application and know how fresh they are. This guide sends a
parameterized GraphQL query through an Endpoint Alias, includes `_meta` so each response reports the
indexed block behind it, and checks for GraphQL errors that can arrive with HTTP `200`.

The example requires `pools`, `token0`, `token1`, and `totalValueLockedUSD` fields from a
Uniswap-style schema. If your Subgraph uses a different schema, adapt the selection using
[Schema reference](../schema-reference). The same request works with a Deployment CID or
Graph Network Subgraph ID endpoint.

## Prerequisites

* An API key that includes Subgraphs.
* A Deployment CID, Graph Network Subgraph ID, or Endpoint Alias for the Subgraph you want to query.
* The GraphQL schema for that Subgraph, or introspection access to discover it.

## Request

This request reads the five pools with the highest total value locked in the current indexed view and returns Subgraph metadata.

CLI · curl

Prerequisites

1. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

2. Replace `<ALIAS>` with your Endpoint Alias.

[Example project](/examples/subgraphs.guides.query-a-subgraph.sh-1.tar.gz)

```sh
# GraphQL errors can arrive with HTTP 200: check the response for an "errors" array.
curl --fail-with-body --silent --show-error "https://subgraphs.graphops.xyz/v1/alias/<ALIAS>" \
  -H "Authorization: Bearer ${GRAPHOPS_API_KEY}" \
  -H "Content-Type: application/json" \
  --data '{
    "query": "query TopPools($first: Int!) { pools(first: $first, orderBy: totalValueLockedUSD, orderDirection: desc) { id token0 { symbol } token1 { symbol } totalValueLockedUSD } _meta { block { number hash } hasIndexingErrors } }",
    "variables": { "first": 5 },
    "operationName": "TopPools"
  }'

```

Output

```json
{
  "data": {
    "pools": [
      {
        "id": "0x277667eb3e34f134adf870be9550e9f323d0dc24",
        "token0": {
          "symbol": "ease.org"
        },
        "token1": {
          "symbol": "ez-cvxsteCRV"
        },
        "totalValueLockedUSD": "1110167010695.785900004139211677005"
      },
      {
        "id": "0x8c0411f2ad5470a66cb2e9c64536cfb8dcd54d51",
        "token0": {
          "symbol": "ease.org"
        },
        "token1": {
          "symbol": "ez-yvCurve-IronBank"
        },
        "totalValueLockedUSD": "1432077483.208630196467118329099649"
      },
      {
        "id": "0x055284a4ca6532ecc219ac06b577d540c686669d",
        "token0": {
          "symbol": "ease.org"
        },
        "token1": {
          "symbol": "ez-SLP-WBTC-WETH"
        },
        "totalValueLockedUSD": "1322031013.848042060988788389158996"
      },
      {
        "id": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
        "token0": {
          "symbol": "USDC"
        },
        "token1": {
          "symbol": "WETH"
        },
        "totalValueLockedUSD": "385191967.4113592219436945119116405"
      },
      {
        "id": "0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
        "token0": {
          "symbol": "USDC"
        },
        "token1": {
          "symbol": "WETH"
        },
        "totalValueLockedUSD": "321144439.2777974484977405304295032"
      }
    ],
    "_meta": {
      "block": {
        "number": 26285622,
        "hash": "0x0d79b8e3597d041e44c63645f9ea378a6fb856830bb663afc5e56eb26d3e72fa"
      },
      "hasIndexingErrors": false
    }
  }
}
```

Up to $first pools, largest first

BigDecimal values arrive as strings

The data reflects this block

Treat true as a data-quality warning

TypeScript · fetch

Prerequisites

1. Install Node.js.

2. Install tsx. `npm install tsx`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

4. Replace `<ALIAS>` with your Endpoint Alias.

Tested with Node.js 24.22.1, tsx 4.23.15.

[Example project](/examples/subgraphs.guides.query-a-subgraph.ts-2.tar.gz)

```typescript
export {};

const response = await fetch(
  "https://subgraphs.graphops.xyz/v1/alias/<ALIAS>",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.GRAPHOPS_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: `
        query TopPools($first: Int!) {
          pools(
            first: $first
            orderBy: totalValueLockedUSD
            orderDirection: desc
          ) {
            id
            token0 { symbol }
            token1 { symbol }
            totalValueLockedUSD
          }
          _meta {
            block { number hash }
            hasIndexingErrors
          }
        }
      `,
      variables: { first: 5 },
      operationName: "TopPools",
    }),
  },
);
if (!response.ok) throw new Error(await response.text());

const { data, errors } = await response.json();
// GraphQL errors can arrive with HTTP 200, so check the body too.
if (errors) throw new Error(JSON.stringify(errors));

console.log(JSON.stringify(data.pools));
// The indexed block these results were read from.
console.log(JSON.stringify(data._meta.block.number));

```

Output

```json
[
  {
    "id": "0x277667eb3e34f134adf870be9550e9f323d0dc24",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-cvxsteCRV"
    },
    "totalValueLockedUSD": "1110167010695.785900004139211677005"
  },
  {
    "id": "0x8c0411f2ad5470a66cb2e9c64536cfb8dcd54d51",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-yvCurve-IronBank"
    },
    "totalValueLockedUSD": "1432077483.208630196467118329099649"
  },
  {
    "id": "0x055284a4ca6532ecc219ac06b577d540c686669d",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-SLP-WBTC-WETH"
    },
    "totalValueLockedUSD": "1322031013.848042060988788389158996"
  },
  {
    "id": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
    "token0": {
      "symbol": "USDC"
    },
    "token1": {
      "symbol": "WETH"
    },
    "totalValueLockedUSD": "385191967.4113592219436945119116405"
  },
  {
    "id": "0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
    "token0": {
      "symbol": "USDC"
    },
    "token1": {
      "symbol": "WETH"
    },
    "totalValueLockedUSD": "321144439.2777974484977405304295032"
  }
]
26285622
```

BigDecimal values arrive as strings

Go · net/http

Prerequisites

1. Install Go.

2. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

3. Replace `<ALIAS>` with your Endpoint Alias.

Tested with Go 1.26.0.

[Example project](/examples/subgraphs.guides.query-a-subgraph.go-5.tar.gz)

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"time"
)

func main() {
	payload, err := json.Marshal(struct {
		Query         string         `json:"query"`
		Variables     map[string]any `json:"variables"`
		OperationName string         `json:"operationName"`
	}{
		Query: `
        query TopPools($first: Int!) {
          pools(
            first: $first
            orderBy: totalValueLockedUSD
            orderDirection: desc
          ) {
            id
            token0 { symbol }
            token1 { symbol }
            totalValueLockedUSD
          }
          _meta {
            block { number hash }
            hasIndexingErrors
          }
        }
        `,
		Variables:     map[string]any{"first": 5},
		OperationName: "TopPools",
	})
	if err != nil {
		log.Fatal(err)
	}

	req, err := http.NewRequest(http.MethodPost,
		"https://subgraphs.graphops.xyz/v1/alias/<ALIAS>", bytes.NewReader(payload))
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("GRAPHOPS_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	resp, err := (&http.Client{Timeout: 30 * time.Second}).Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		log.Fatalf("HTTP %d: %s", resp.StatusCode, body)
	}

	var result struct {
		Data struct {
			Pools json.RawMessage `json:"pools"`
			Meta  struct {
				Block struct {
					Number json.RawMessage `json:"number"`
				} `json:"block"`
			} `json:"_meta"`
		} `json:"data"`
		Errors json.RawMessage `json:"errors"`
	}
	if err := json.Unmarshal(body, &result); err != nil {
		log.Fatal(err)
	}
	// GraphQL errors can arrive with HTTP 200, so check the body too.
	if result.Errors != nil {
		log.Fatalf("GraphQL errors: %s", result.Errors)
	}

	var pools bytes.Buffer
	if err := json.Compact(&pools, result.Data.Pools); err != nil {
		log.Fatal(err)
	}
	fmt.Println(pools.String())
	// The indexed block these results were read from.
	fmt.Println(string(result.Data.Meta.Block.Number))
}

```

Output

```json
[
  {
    "id": "0x277667eb3e34f134adf870be9550e9f323d0dc24",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-cvxsteCRV"
    },
    "totalValueLockedUSD": "1110167010695.785900004139211677005"
  },
  {
    "id": "0x8c0411f2ad5470a66cb2e9c64536cfb8dcd54d51",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-yvCurve-IronBank"
    },
    "totalValueLockedUSD": "1432077483.208630196467118329099649"
  },
  {
    "id": "0x055284a4ca6532ecc219ac06b577d540c686669d",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-SLP-WBTC-WETH"
    },
    "totalValueLockedUSD": "1322031013.848042060988788389158996"
  },
  {
    "id": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
    "token0": {
      "symbol": "USDC"
    },
    "token1": {
      "symbol": "WETH"
    },
    "totalValueLockedUSD": "385191967.4113592219436945119116405"
  },
  {
    "id": "0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
    "token0": {
      "symbol": "USDC"
    },
    "token1": {
      "symbol": "WETH"
    },
    "totalValueLockedUSD": "321144439.2777974484977405304295032"
  }
]
26285622
```

BigDecimal values arrive as strings

Rust · reqwest

Prerequisites

1. Install Rust.

2. Install reqwest, serde\_json, and tokio. `cargo add reqwest serde_json tokio -F reqwest/json -F tokio/macros -F tokio/rt-multi-thread`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

4. Replace `<ALIAS>` with your Endpoint Alias.

Tested with Rust 1.98.1, reqwest 0.13.5, serde\_json 1.0.145, tokio 1.48.0.

[Example project](/examples/subgraphs.guides.query-a-subgraph.rust-6.tar.gz)

```rust
use serde_json::{json, Value};
use std::{env, error::Error, time::Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let response = reqwest::Client::new()
        .post("https://subgraphs.graphops.xyz/v1/alias/<ALIAS>")
        .bearer_auth(env::var("GRAPHOPS_API_KEY")?)
        .timeout(Duration::from_secs(30))
        .json(&json!({
            "query": r#"
        query TopPools($first: Int!) {
          pools(
            first: $first
            orderBy: totalValueLockedUSD
            orderDirection: desc
          ) {
            id
            token0 { symbol }
            token1 { symbol }
            totalValueLockedUSD
          }
          _meta {
            block { number hash }
            hasIndexingErrors
          }
        }
        "#,
            "variables": { "first": 5 },
            "operationName": "TopPools",
        }))
        .send()
        .await?
        .error_for_status()?;
    let result: Value = response.json().await?;
    // GraphQL errors can arrive with HTTP 200, so check the body too.
    if let Some(errors) = result.get("errors") {
        return Err(errors.to_string().into());
    }

    println!("{}", result["data"]["pools"]);
    // The indexed block these results were read from.
    println!("{}", result["data"]["_meta"]["block"]["number"]);
    Ok(())
}

```

Output

```json
[
  {
    "id": "0x277667eb3e34f134adf870be9550e9f323d0dc24",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-cvxsteCRV"
    },
    "totalValueLockedUSD": "1110167010695.785900004139211677005"
  },
  {
    "id": "0x8c0411f2ad5470a66cb2e9c64536cfb8dcd54d51",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-yvCurve-IronBank"
    },
    "totalValueLockedUSD": "1432077483.208630196467118329099649"
  },
  {
    "id": "0x055284a4ca6532ecc219ac06b577d540c686669d",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-SLP-WBTC-WETH"
    },
    "totalValueLockedUSD": "1322031013.848042060988788389158996"
  },
  {
    "id": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
    "token0": {
      "symbol": "USDC"
    },
    "token1": {
      "symbol": "WETH"
    },
    "totalValueLockedUSD": "385191967.4113592219436945119116405"
  },
  {
    "id": "0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
    "token0": {
      "symbol": "USDC"
    },
    "token1": {
      "symbol": "WETH"
    },
    "totalValueLockedUSD": "321144439.2777974484977405304295032"
  }
]
26285622
```

BigDecimal values arrive as strings

Python · requests

Prerequisites

1. Install Python.

2. Install requests. `python -m pip install requests`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

4. Replace `<ALIAS>` with your Endpoint Alias.

Tested with Python 3.12.12, requests 2.34.2.

[Example project](/examples/subgraphs.guides.query-a-subgraph.python-4.tar.gz)

```python
import json
import os

import requests

response = requests.post(
    "https://subgraphs.graphops.xyz/v1/alias/<ALIAS>",
    headers={
        "Authorization": f"Bearer {os.environ['GRAPHOPS_API_KEY']}",
    },
    json={
        "query": """
        query TopPools($first: Int!) {
          pools(
            first: $first
            orderBy: totalValueLockedUSD
            orderDirection: desc
          ) {
            id
            token0 { symbol }
            token1 { symbol }
            totalValueLockedUSD
          }
          _meta {
            block { number hash }
            hasIndexingErrors
          }
        }
        """,
        "variables": {"first": 5},
        "operationName": "TopPools",
    },
    timeout=30,
)
response.raise_for_status()
result = response.json()
# GraphQL errors can arrive with HTTP 200, so check the body too.
if "errors" in result:
    raise RuntimeError(result["errors"])

print(json.dumps(result["data"]["pools"]))
# The indexed block these results were read from.
print(json.dumps(result["data"]["_meta"]["block"]["number"]))

```

Output

```json
[
  {
    "id": "0x277667eb3e34f134adf870be9550e9f323d0dc24",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-cvxsteCRV"
    },
    "totalValueLockedUSD": "1110167010695.785900004139211677005"
  },
  {
    "id": "0x8c0411f2ad5470a66cb2e9c64536cfb8dcd54d51",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-yvCurve-IronBank"
    },
    "totalValueLockedUSD": "1432077483.208630196467118329099649"
  },
  {
    "id": "0x055284a4ca6532ecc219ac06b577d540c686669d",
    "token0": {
      "symbol": "ease.org"
    },
    "token1": {
      "symbol": "ez-SLP-WBTC-WETH"
    },
    "totalValueLockedUSD": "1322031013.848042060988788389158996"
  },
  {
    "id": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
    "token0": {
      "symbol": "USDC"
    },
    "token1": {
      "symbol": "WETH"
    },
    "totalValueLockedUSD": "385191967.4113592219436945119116405"
  },
  {
    "id": "0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
    "token0": {
      "symbol": "USDC"
    },
    "token1": {
      "symbol": "WETH"
    },
    "totalValueLockedUSD": "321144439.2777974484977405304295032"
  }
]
26285622
```

BigDecimal values arrive as strings

## Handle the result

* Check for an `errors` array before you read `data`. GraphQL errors can arrive with HTTP `200`,
and a response can contain both `data` and `errors`.
* Treat an empty list as a valid result, not a failure.
* Read `_meta.block.number` when you display or store the data, and alert when
`_meta.hasIndexingErrors` is `true`.
* Log the [`X-Deployment-CID` response header](../api#response-headers) with results you store, so
you can tell which deployment produced them after an Endpoint Alias moves.
* Request only the fields your application renders or stores, and page through larger collections.

Use Endpoint Aliases for application endpoints when your team needs controlled upgrades. Use
Deployment CIDs for tests and rollback targets that must stay on one
immutable deployment.

## Next steps

* [Paginate results](./paginate-results): Read a whole collection in bounded, resumable pages.
* [Monitor sync health](./monitor-sync-health): Turn `_meta` into lag and error alerts.
* [API integration](../api): Check the request envelope, endpoint shapes, and error responses.