6 minutes
GraphQL API
Explore the GraphQL Query API for interacting with Subgraphs on The Graph Network.
GraphQL is a query language for APIs and a runtime for executing those queries with existing data.
The Graph uses GraphQL to query Subgraphs.
Core Concepts
Entities
- What they are: Persistent data objects defined with
@entityin your schema - Key requirement: Must contain
id: ID!as primary identifier - Usage: Foundation for all query operations
Schema
- Purpose: Blueprint defining the data structure and relationships using GraphQL IDL
- Key characteristics:
- Auto-generates query endpoints
- Read-only operations (no mutations)
- Defines entity interfaces and derived fields
Query Structure
GraphQL queries in The Graph target entities defined in the Subgraph schema. Each Entity type generates corresponding entity and entities fields on the root Query type.
Note: The query keyword is not required at the top level of GraphQL queries.
Single Entity Queries Example
Query for a single Token entity:
1{2 token(id: "1") {3 id4 owner5 }6}Note: Single entity queries require the id parameter as a string.
Collection Queries Example
Query format for all Token entities:
1{2 tokens {3 id4 owner5 }6}Sorting Example
Collection queries support the following sort parameters:
orderBy: Specifies the attribute for sortingorderDirection: Acceptsasc(ascending) ordesc(descending)
Standard Sorting Example
1{2 tokens(orderBy: price, orderDirection: asc) {3 id4 owner5 }6}Nested Entity Sorting Example
1{2 tokens(orderBy: owner__name, orderDirection: asc) {3 id4 owner {5 name6 }7 }8}Note: Nested sorting supports one-level-deep String or ID types on @entity and @derivedFrom fields.
Pagination Example
When querying a collection, it is best to:
- Use the
firstparameter to paginate from the beginning of the collection.- The default sort order is by
IDin ascending alphanumeric order, not by creation time.
- The default sort order is by
- Use the
skipparameter to skip entities and paginate. For instance,first:100shows the first 100 entities andfirst:100, skip:100shows the next 100 entities. - Avoid using
skipvalues in queries because they generally perform poorly. To retrieve a large number of items, it’s best to page through entities based on an attribute as shown in the previous example above.
Standard Pagination Example
1{2 tokens(first: 10) {3 id4 owner5 }6}Offset Pagination Example
1{2 tokens(first: 10, skip: 10) {3 id4 owner5 }6}Cursor-based Pagination Example
1query manyTokens($lastID: String) {2 tokens(first: 1000, where: { id_gt: $lastID }) {3 id4 owner5 }6}Filtering
The where parameter filters entities based on specified conditions.
Basic Filtering Example
1{2 challenges(where: { outcome: "failed" }) {3 challenger4 outcome5 application {6 id7 }8 }9}Numeric Comparison Example
1{2 applications(where: { deposit_gt: "10000000000" }) {3 id4 whitelisted5 deposit6 }7}Block-based Filtering Example
1{2 applications(where: { _change_block: { number_gte: 100 } }) {3 id4 whitelisted5 deposit6 }7}Nested Entity Filtering Example
1{2 challenges(where: { application_: { id: 1 } }) {3 challenger4 outcome5 application {6 id7 }8 }9}Logical Operators
AND Operations Example
The following example filters for challenges with outcome succeeded and number greater than or equal to 100.
1{2 challenges(where: { and: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {3 challenger4 outcome5 application {6 id7 }8 }9}Syntactic sugar: You can simplify the above query by removing the and operator and by passing a sub-expression separated by commas.
1{2 challenges(where: { number_gte: 100, outcome: "succeeded" }) {3 challenger4 outcome5 application {6 id7 }8 }9}OR Operations Example
1{2 challenges(where: { or: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {3 challenger4 outcome5 application {6 id7 }8 }9}Global filter parameter:
1_change_block(number_gte: Int)Time-travel Queries Example
Queries support historical state retrieval using the block parameter:
number: Integer block numberhash: String block hash
Note: The current implementation is still subject to certain limitations that might violate these guarantees. The implementation can not always tell that a given block hash is not on the main chain at all, or if a query result by a block hash for a block that is not yet considered final could be influenced by a block reorganization running concurrently with the query. They do not affect the results of queries by block hash when the block is final and known to be on the main chain. This issue explains what these limitations are in detail.
Block Number Query Example
1{2 challenges(block: { number: 8000000 }) {3 challenger4 outcome5 application {6 id7 }8 }9}Block Hash Query Example
1{2 challenges(block: { hash: "0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c" }) {3 challenger4 outcome5 application {6 id7 }8 }9}Full-Text Search Example
Full-text search query fields provide an expressive text search API that can be added to the Subgraph schema and customized. Refer to Defining Full-text Search Fields to add full-text search to your Subgraph.
Full-text search queries have one required field, text, for supplying search terms. Several special full-text operators are available to be used in this text search field.
Full-text search fields use the required text parameter with the following operators:
| Operator | Symbol | Description |
|---|---|---|
| And | & | Matches entities containing all terms |
| Or | | | Return all entities with a match from any of the provided terms |
| Follow by | <-> | Matches terms with specified distance |
| Prefix | :* | Matches word prefixes (minimum 2 characters) |
Search Examples
OR operator:
1{2 blogSearch(text: "anarchism | crumpets") {3 id4 title5 body6 author7 }8}“Follow” by operator:
1{2 blogSearch(text: "decentralized <-> philosophy") {3 id4 title5 body6 author7 }8}Combined operators:
1{2 blogSearch(text: "lou:* <-> music") {3 id4 title5 body6 author7 }8}Schema Definition
Entity types require:
- GraphQL Interface Definition Language (IDL) format
@entitydirectiveIDfield
Subgraph Metadata Example
The _Meta_ object provides subgraph metadata:
1{2 _meta(block: { number: 123987 }) {3 block {4 number5 hash6 timestamp7 }8 deployment9 hasIndexingErrors10 }11}Metadata fields:
deployment: IPFS CID of the subgraph.yamlblock: Latest block informationhasIndexingErrors: Boolean indicating past indexing errors
Note: When writing queries, it is important to consider the performance impact of using the or operator. While or can be a useful tool for broadening search results, it can also have significant costs. One of the main issues with or is that it can cause queries to slow down. This is because or requires the database to scan through multiple indexes, which can be a time-consuming process. To avoid these issues, it is recommended that developers use and operators instead of or whenever possible. This allows for more precise filtering and can lead to faster, more accurate queries.
GraphQL Filter Operators Reference
This table explains each filter operator available in The Graph’s GraphQL API. These operators are used as suffixes to field names when filtering data using the where parameter.
| Operator | Description | Example |
|---|---|---|
_ | Matches entities where the specified field equals another entity | { where: { owner_: { name: "Alice" } } } |
_not | Negates the specified condition | { where: { active_not: true } } |
_gt | Greater than (>) | { where: { price_gt: "100" } } |
_lt | Less than (\<) | { where: { price_lt: "100" } } |
_gte | Greater than or equal to (>=) | { where: { price_gte: "100" } } |
_lte | Less than or equal to (\<=) | { where: { price_lte: "100" } } |
_in | Value is in the specified array | { where: { category_in: ["Art", "Music"] } } |
_not_in | Value is not in the specified array | { where: { category_not_in: ["Art", "Music"] } } |
_contains | Field contains the specified string (case-sensitive) | { where: { name_contains: "token" } } |
_contains_nocase | Field contains the specified string (case-insensitive) | { where: { name_contains_nocase: "token" } } |
_not_contains | Field does not contain the specified string (case-sensitive) | { where: { name_not_contains: "test" } } |
_not_contains_nocase | Field does not contain the specified string (case-insensitive) | { where: { name_not_contains_nocase: "test" } } |
_starts_with | Field starts with the specified string (case-sensitive) | { where: { name_starts_with: "Crypto" } } |
_starts_with_nocase | Field starts with the specified string (case-insensitive) | { where: { name_starts_with_nocase: "crypto" } } |
_ends_with | Field ends with the specified string (case-sensitive) | { where: { name_ends_with: "Token" } } |
_ends_with_nocase | Field ends with the specified string (case-insensitive) | { where: { name_ends_with_nocase: "token" } } |
_not_starts_with | Field does not start with the specified string (case-sensitive) | { where: { name_not_starts_with: "Test" } } |
_not_starts_with_nocase | Field does not start with the specified string (case-insensitive) | { where: { name_not_starts_with_nocase: "test" } } |
_not_ends_with | Field does not end with the specified string (case-sensitive) | { where: { name_not_ends_with: "Test" } } |
_not_ends_with_nocase | Field does not end with the specified string (case-insensitive) | { where: { name_not_ends_with_nocase: "test" } } |
Notes
- Type support varies by operator. For example,
Booleanonly supports_not,_in, and_not_in. - The
_operator is only available for object and interface types. - String comparison operators are especially useful for text fields.
- Numeric comparison operators work with both number and string-encoded number fields.
- Use these operators in combination with logical operators (
and,or) for complex filtering.
Validation
Graph Node implements specification-based validation of the GraphQL queries it receives using graphql-tools-rs, which is based on the graphql-js reference implementation. Queries which fail a validation rule do so with a standard error - visit the GraphQL spec to learn more.