GraphQL API
Reading time: 11 minutes
Learn about the GraphQL Query API used in The Graph.
What is GraphQL?
GraphQL is a query language for APIs and a runtime for executing those queries with your existing data. The Graph uses GraphQL to query subgraphs.
To understand the larger role that GraphQL plays, review developing and creating a subgraph.
Queries with GraphQL
In your subgraph schema you define types called Entities
. For each Entity
type, entity
and entities
fields will be generated on the top-level Query
type.
Note: query
does not need to be included at the top of the graphql
query when using The Graph.
例子
Query for a single Token
entity defined in your schema:
{ token(id: "1") { id owner }}
Note: When querying for a single entity, the id
field is required, and it must be written as a string.
Query all Token
entities:
{ tokens { id owner }}
排序
When querying a collection, you may:
- Use the
orderBy
parameter to sort by a specific attribute. - Use the
orderDirection
to specify the sort direction,asc
for ascending ordesc
for descending.
示例
{ tokens(orderBy: price, orderDirection: asc) { id owner }}
嵌套实体筛选示例
As of Graph Node 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:
{ tokens(orderBy: owner__name, orderDirection: asc) { id owner { name } }}
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, sorting by fields which are arrays and nested entities is not yet supported.
分页
When querying a collection, it’s 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.
Example using first
查询前10 个代币:
{ tokens(first: 10) { id owner }}
To query for groups of entities in the middle of a collection, the skip
parameter may 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:
{ tokens(first: 10, skip: 10) { id owner }}
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:
query manyTokens($lastID: String) { tokens(first: 1000, where: { id_gt: $lastID }) { id owner } }}
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.
过滤
- You can use the
where
parameter in your queries to filter for different properties. - You can filter on multiple values within the
where
parameter.
Example using where
Query challenges with failed
outcome:
{ challenges(where: { outcome: "failed" }) { challenger outcome application { id } }}
You can use suffixes like _gt
, _lte
for value comparison:
范围过滤示例
{ applications(where: { deposit_gt: "10000000000" }) { id whitelisted deposit }}
区块过滤示例
You can also filter entities that were updated in or after a specified block with _change_block(number_gte: Int)
.
如果您只想获取已经更改的实体,例如自上次轮询以来改变的实体,那么这将非常有用。或者也可以调查或调试子图中实体的变化情况(如果与区块过滤器结合使用,则只能隔离在特定区块中发生变化的实体)。
{ applications(where: { _change_block: { number_gte: 100 } }) { id whitelisted deposit }}
嵌套实体筛选示例
Filtering on the basis of nested entities is possible in the fields with the _
suffix.
如果您希望只获取其子级实体满足条件的实体,那么这可能很有用。
{ challenges(where: { application_: { id: 1 } }) { challenger outcome application { id } }}
逻辑运算符
As of Graph Node 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.
AND
Operator
The following example filters for challenges with outcome
succeeded
and number
greater than or equal to 100
.
{ challenges(where: { and: [{ number_gte: 100 }, { outcome: "succeeded" }] }) { challenger outcome application { id } }}
Syntactic sugar: You can simplify the above query by removing the and
operator by passing a sub-expression separated by commas.
{ challenges(where: { number_gte: 100, outcome: "succeeded" }) { challenger outcome application { id } }}
OR
Operator
The following example filters for challenges with outcome
succeeded
or number
greater than or equal to 100
.
{ challenges(where: { or: [{ number_gte: 100 }, { outcome: "succeeded" }] }) { challenger outcome application { id } }}
Note: When constructing 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.
所有过滤器
参数后缀的完整列表:
__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
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:
_change_block(number_gte: Int)
跨时间查询
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.
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.
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.
示例
{ challenges(block: { number: 8000000 }) { challenger outcome application { id } }}
This query will return Challenge
entities, and their associated Application
entities, as they existed directly after processing block number 8,000,000.
示例
{ challenges(block: { hash: "0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c" }) { challenger outcome application { id } }}
This query will return Challenge
entities, and their associated Application
entities, as they existed directly after processing the block with the given hash.
全文搜索查询
Fulltext search query fields provide an expressive text search API that can be added to the subgraph schema and customized. Refer to Defining Fulltext Search Fields to add fulltext search to your subgraph.
Fulltext search queries have one required field, text
, for supplying search terms. Several special fulltext operators are available to be used in this text
search field.
全文搜索运算符:
符号 | 运算符 | 描述 |
---|---|---|
& | And | 用于将多个搜索词组合到包含所有提供词条的实体的过滤器中 |
| | Or | 由 or 运算符分隔的多个搜索词的查询,将返回与任何提供的词匹配的所有实体 |
<-> | Follow by | 指定两个单词之间的距离。 |
:* | Prefix | 使用前缀搜索词查找前缀匹配的单词(需要 2 个字符) |
例子
Using the or
operator, this query will filter to blog entities with variations of either “anarchism” or “crumpet” in their fulltext fields.
{ blogSearch(text: "anarchism | crumpets") { id title body author }}
The follow by
operator specifies a words a specific distance apart in the fulltext documents. The following query will return all blogs with variations of “decentralize” followed by “philosophy”
{ blogSearch(text: "decentralized <-> philosophy") { id title body author }}
可以将全文运算符进行组合来制作更复杂的过滤器。 在下面的查询示例中,使用前缀搜索运算符与其他运算符的结合,可以实现匹配所有以“lou”开头后,跟着“music”单词的日志实体。
{ blogSearch(text: "lou:* <-> music") { id title body author }}
验证
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.
模式
The schema of your dataSources, i.e. the entity types, values, and relationships that are available to query, are defined through the GraphQL Interface Definition Language (IDL).
GraphQL schemas generally define root types for queries
, subscriptions
and mutations
. The Graph only supports queries
. The root Query
type for your subgraph is automatically generated from the GraphQL schema that’s included in your subgraph manifest.
Note: Our API does not expose mutations because developers are expected to issue transactions directly against the underlying blockchain from their applications.
实体
All GraphQL types with @entity
directives in your schema will be treated as entities and must have an ID
field.
Note: Currently, all types in your schema must have an @entity
directive. In the future, we will treat types without an @entity
directive as value objects, but this is not yet supported.
子图元数据
All subgraphs have an auto-generated _Meta_
object, which provides access to subgraph metadata. This can be queried as follows:
{ _meta(block: { number: 123987 }) { block { number hash timestamp } deployment hasIndexingErrors }}
如果提供了区块,则元数据为该区块的元数据,如果未使用最新的索引区块。如果提供,则区块必须在子图的起始区块之后,并且小于或等于最近索引的区块。
deployment
is a unique ID, corresponding to the IPFS CID of the subgraph.yaml
file.
block
provides information about the latest block (taking into account any block constraints passed to _meta
):
- hash:区块的哈希
- number:区块编号
- timestamp:区块的时间戳(如果可用)(当前仅适用于索引EVM网络的子图)
hasIndexingErrors
is a boolean identifying whether the subgraph encountered indexing errors at some past block