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
@entity
in 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
first
parameter to paginate from the beginning of the collection.- The default sort order is by
ID
in ascending alphanumeric order, not by creation time.
- The default sort order is by
- Use the
skip
parameter to skip entities and paginate. For instance,first:100
shows the first 100 entities andfirst:100, skip:100
shows the next 100 entities. - Avoid using
skip
values 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
@entity
directiveID
field
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,
Boolean
only 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.