diff --git a/website/src/pages/en/subgraphs/querying/graphql-api.mdx b/website/src/pages/en/subgraphs/querying/graphql-api.mdx index bd3cdf2f8a86..7263db28f017 100644 --- a/website/src/pages/en/subgraphs/querying/graphql-api.mdx +++ b/website/src/pages/en/subgraphs/querying/graphql-api.mdx @@ -4,9 +4,9 @@ title: GraphQL API Explore the GraphQL Query API for interacting with Subgraphs on The Graph Network. -## What is GraphQL? +[GraphQL](https://graphql.org/learn/) is a query language for APIs and a runtime for executing those queries with existing data. -[GraphQL](https://graphql.org/learn/) is a query language for APIs and a runtime for executing those queries with your existing data. The Graph uses GraphQL to query Subgraphs. +The Graph uses GraphQL to query Subgraphs. ## Core Concepts @@ -24,15 +24,15 @@ Explore the GraphQL Query API for interacting with Subgraphs on The Graph Networ - Read-only operations (no mutations) - Defines entity interfaces and derived fields -## Queries with GraphQL +## Query Structure -In the Subgraph schema, types called `Entities`. For each `Entity` type, `entity` and `entities` fields will be generated on the top-level `Query` type. +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. -### Example Queries +> Note: The `query` keyword is not required at the top level of GraphQL queries. -> Note: `query` does not need to be included at the top of the `graphql` query when using The Graph. +### Single Entity Queries Example -Query for a single `Token` entity defined in your schema: +Query for a single `Token` entity: ```graphql { @@ -43,9 +43,11 @@ Query for a single `Token` entity defined in your schema: } ``` -> Note: When querying for a single entity, the `id` field is required, and it must be written as a string. +> Note: Single entity queries require the `id` parameter as a string. -Query all `Token` entities: +### Collection Queries Example + +Query format for all `Token` entities: ```graphql { @@ -56,14 +58,14 @@ Query all `Token` entities: } ``` -### Sorting +### Sorting Example -When querying a collection, you can: +Collection queries support the following sort parameters: -- Use the `orderBy` parameter to sort by a specific attribute. -- Use the `orderDirection` to specify the sort direction, `asc` for ascending or `desc` for descending. +- `orderBy`: Specifies the attribute for sorting +- `orderDirection`: Accepts `asc` (ascending) or `desc` (descending) -#### Example +#### Standard Sorting Example ```graphql { @@ -74,11 +76,7 @@ When querying a collection, you can: } ``` -#### Example for Nested Entity Sorting - -As of Graph Node [`v0.30.0`](https://github.com/graphprotocol/graph-node/releases/tag/v0.30.0) entities can be sorted on the basis of nested entities. - -The following example shows tokens sorted by the name of their owner: +#### Nested Entity Sorting Example ```graphql { @@ -91,20 +89,18 @@ The following example shows tokens sorted by the name of their owner: } ``` -> Currently, you can sort by one-level deep `String` or `ID` types on `@entity` and `@derivedFrom` fields. Unfortunately, [sorting by interfaces on one level-deep entities](https://github.com/graphprotocol/graph-node/pull/4058), sorting by fields which are arrays and nested entities is not yet supported. +> Note: Nested sorting supports one-level-deep `String` or `ID` types on `@entity` and `@derivedFrom` fields. -### Pagination +### Pagination Example -When querying a collection, it's best to: +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. - Use the `skip` parameter to skip entities and paginate. For instance, `first:100` shows the first 100 entities and `first: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. -#### Example Using `first` - -Query the first 10 tokens: +#### Standard Pagination Example ```graphql { @@ -115,11 +111,7 @@ Query the first 10 tokens: } ``` -To query for groups of entities in the middle of a collection, the `skip` parameter can be used in conjunction with the `first` parameter to skip a specified number of entities starting at the beginning of the collection. - -#### Example Using `first` and `skip` - -Query 10 `Token` entities, offset by 10 places from the beginning of the collection: +#### Offset Pagination Example ```graphql { @@ -130,9 +122,7 @@ Query 10 `Token` entities, offset by 10 places from the beginning of the collect } ``` -#### Example Using `first` and `id_ge` - -If a client needs to retrieve a large number of entities, it's more performant to base queries on an attribute and filter by that attribute. For example, a client could retrieve a large number of tokens using this query: +#### Cursor-based Pagination Example ```graphql query manyTokens($lastID: String) { @@ -143,16 +133,11 @@ query manyTokens($lastID: String) { } ``` -The first time, it would send the query with `lastID = ""`, and for subsequent requests it would set `lastID` to the `id` attribute of the last entity in the previous request. This approach will perform significantly better than using increasing `skip` values. - ### Filtering -- You can use the `where` parameter in your queries to filter for different properties. -- You can filter on multiple values within the `where` parameter. - -#### Using `where` Filtering +The `where` parameter filters entities based on specified conditions. -Query challenges with `failed` outcome using 'where' filter: +#### Basic Filtering Example ```graphql { @@ -166,9 +151,7 @@ Query challenges with `failed` outcome using 'where' filter: } ``` -You can use suffixes like `_gt`, `_lte` for value comparison: - -#### Range Filtering +#### Numeric Comparison Example ```graphql { @@ -180,11 +163,7 @@ You can use suffixes like `_gt`, `_lte` for value comparison: } ``` -#### Block Filtering - -You can also filter entities that were updated in or after a specified block with `_change_block(number_gte: Int)`. - -This can be useful if you are looking to fetch only entities which have changed, for example since the last time you polled. Or alternatively it can be useful to investigate or debug how entities are changing in your Subgraph (if combined with a block filter, you can isolate only entities that changed in a specific block). +#### Block-based Filtering Example ```graphql { @@ -196,11 +175,7 @@ This can be useful if you are looking to fetch only entities which have changed, } ``` -#### Nested Entity Filtering - -Filtering on the basis of nested entities is possible in the fields with the `_` suffix. - -This can be useful if you are looking to fetch only entities whose child-level entities meet the provided conditions. +#### Nested Entity Filtering Example ```graphql { @@ -214,11 +189,9 @@ This can be useful if you are looking to fetch only entities whose child-level e } ``` -### Logical Operators - -As of Graph Node [`v0.30.0`](https://github.com/graphprotocol/graph-node/releases/tag/v0.30.0) you can group multiple parameters in the same `where` argument using the `and` or the `or` operators to filter results based on more than one criteria. +#### Logical Operators -#### Using `and` Operator +##### AND Operations Example The following example filters for challenges with `outcome` `succeeded` and `number` greater than or equal to `100`. @@ -234,27 +207,11 @@ The following example filters for challenges with `outcome` `succeeded` and `num } ``` -> **Syntactic sugar:** You can simplify the above query by removing the `and` operator by passing a sub-expression separated by commas. -> -> ```graphql -> { -> challenges(where: { number_gte: 100, outcome: "succeeded" }) { -> challenger -> outcome -> application { -> id -> } -> } -> } -> ``` - -#### Using `or` Operator - -The following example filters for challenges with `outcome` `succeeded` or `number` greater than or equal to `100`. +**Syntactic sugar:** You can simplify the above query by removing the `and` operator and by passing a sub-expression separated by commas. ```graphql { - challenges(where: { or: [{ number_gte: 100 }, { outcome: "succeeded" }] }) { + challenges(where: { number_gte: 100, outcome: "succeeded" }) { challenger outcome application { @@ -264,52 +221,36 @@ The following example filters for challenges with `outcome` `succeeded` or `numb } ``` -> **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. +##### OR Operations Example -#### All Filters - -Full list of parameter suffixes: - -``` -_ -_not -_gt -_lt -_gte -_lte -_in -_not_in -_contains -_contains_nocase -_not_contains -_not_contains_nocase -_starts_with -_starts_with_nocase -_ends_with -_ends_with_nocase -_not_starts_with -_not_starts_with_nocase -_not_ends_with -_not_ends_with_nocase +```graphql +{ + challenges(where: { or: [{ number_gte: 100 }, { outcome: "succeeded" }] }) { + challenger + outcome + application { + id + } + } +} ``` -> Please note that some suffixes are only supported for specific types. For example, `Boolean` only supports `_not`, `_in`, and `_not_in`, but `_` is available only for object and interface types. - -In addition, the following global filters are available as part of `where` argument: +Global filter parameter: ```graphql _change_block(number_gte: Int) ``` -### Time-travel Queries +### Time-travel Queries Example -You can query the state of your entities not just for the latest block, which is the default, but also for an arbitrary block in the past. The block at which a query should happen can be specified either by its block number or its block hash by including a `block` argument in the toplevel fields of queries. +Queries support historical state retrieval using the `block` parameter: -The result of such a query will not change over time, i.e., querying at a certain past block will return the same result no matter when it is executed, with the exception that if you query at a block very close to the head of the chain, the result might change if that block turns out to **not** be on the main chain and the chain gets reorganized. Once a block can be considered final, the result of the query will not change. +- `number`: Integer block number +- `hash`: 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](https://github.com/graphprotocol/graph-node/issues/1405) explains what these limitations are in detail. -#### Example Time-travel Queries +#### Block Number Query Example ```graphql { @@ -323,7 +264,7 @@ The result of such a query will not change over time, i.e., querying at a certai } ``` -This query will return `Challenge` entities, and their associated `Application` entities, as they existed directly after processing block number 8,000,000. +#### Block Hash Query Example ```graphql { @@ -337,28 +278,26 @@ This query will return `Challenge` entities, and their associated `Application` } ``` -This query will return `Challenge` entities, and their associated `Application` entities, as they existed directly after processing the block with the given hash. - -### Full-text Search Queries +### 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](/developing/creating-a-subgraph/#defining-fulltext-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 operators: +Full-text search fields use the required `text` parameter with the following operators: -| Symbol | Operator | Description | -| --- | --- | --- | -| `&` | `And` | For combining multiple search terms into a filter for entities that include all of the provided terms | -| `\|` | `Or` | Queries with multiple search terms separated by the or operator will return all entities with a match from any of the provided terms | -| `<->` | `Follow by` | Specify the distance between two words. | -| `:*` | `Prefix` | Use the prefix search term to find words whose prefix match (2 characters required.) | +| 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) | -#### Full-text Query Examples +#### Search Examples -Using the `or` operator, this query will filter to blog entities with variations of either "anarchism" or "crumpet" in their full-text fields. +OR operator: -```graphql +``` { blogSearch(text: "anarchism | crumpets") { id @@ -369,7 +308,7 @@ Using the `or` operator, this query will filter to blog entities with variations } ``` -The `follow by` operator specifies that two words must appear a specific distance apart in full-text documents.. The following query will return all blogs with variations of "decentralize" followed by "philosophy" +“Follow” by operator: ```graphql { @@ -382,7 +321,7 @@ The `follow by` operator specifies that two words must appear a specific distanc } ``` -Combine full-text operators to make more complex filters. With a pretext search operator combined with a follow by this example query will match all blog entities with words that start with "lou" followed by "music". +Combined operators: ```graphql { @@ -395,15 +334,19 @@ Combine full-text operators to make more complex filters. With a pretext search } ``` -### Validation +### Schema Definition -Graph Node implements [specification-based](https://spec.graphql.org/October2021/#sec-Validation) validation of the GraphQL queries it receives using [graphql-tools-rs](https://github.com/dotansimha/graphql-tools-rs#validation-rules), which is based on the [graphql-js reference implementation](https://github.com/graphql/graphql-js/tree/main/src/validation). Queries which fail a validation rule do so with a standard error - visit the [GraphQL spec](https://spec.graphql.org/October2021/#sec-Validation) to learn more. +Entity types require: -### Subgraph Metadata +- GraphQL Interface Definition Language (IDL) format +- `@entity` directive +- `ID` field -All Subgraphs have an auto-generated `_Meta_` object, which provides access to Subgraph metadata. This can be queried as follows: +### Subgraph Metadata Example -```graphQL +The `_Meta_` object provides subgraph metadata: + +```graphql { _meta(block: { number: 123987 }) { block { @@ -417,14 +360,49 @@ All Subgraphs have an auto-generated `_Meta_` object, which provides access to S } ``` -If a block is provided, the metadata is as of that block, if not the latest indexed block is used. If provided, the block must be after the Subgraph's start block, and less than or equal to the most recently indexed block. +Metadata fields: + +- `deployment`: IPFS CID of the subgraph.yaml +- `block`: Latest block information +- `hasIndexingErrors`: Boolean indicating past indexing errors -`deployment` is a unique ID, corresponding to the IPFS CID of the `subgraph.yaml` file. +> 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. -`block` provides information about the latest block (taking into account any block constraints passed to `_meta`): +### GraphQL Filter Operators Reference -- hash: the hash of the block -- number: the block number -- timestamp: the timestamp of the block, if available (this is currently only available for Subgraphs indexing EVM networks) +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. -`hasIndexingErrors` is a boolean identifying whether the Subgraph encountered indexing errors at some past block +| 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](https://spec.graphql.org/October2021/#sec-Validation) validation of the GraphQL queries it receives using [graphql-tools-rs](https://github.com/dotansimha/graphql-tools-rs#validation-rules), which is based on the [graphql-js reference implementation](https://github.com/graphql/graphql-js/tree/main/src/validation). Queries which fail a validation rule do so with a standard error - visit the [GraphQL spec](https://spec.graphql.org/October2021/#sec-Validation) to learn more.