Skip to main content

GraphQL RPC

info

The GraphQL RPC service is currently under development. The MVP is scheduled to be launched at the end of January 2024.

This document explains some of the common concepts when working with GraphQL such as pagination, fragments, or variables. For an introduction to GraphQL, see GitHub's Introduction to GraphQL.

If you are interested in how to interact with the Sui network via the GraphQL RPC, see Getting Started.

Discovering the schema

GraphQL offers an introspection feature that allows you to query for the schema that is loaded by a service instance. The official documentation provides an overview on introspection.

Headers

The service accepts the following optional headers:

  • x-sui-rpc-version to specify which RPC version to use (note that this is currently unavailable)
  • x-sui-rpc-show-usage will return the response with extra query complexity information.

By default, each request will return the service's version in the response header: x-sui-rpc-version.

curl -v -X POST https://graphql-beta.mainnet.sui.io \
--header 'x-sui-rpc-show-usage: true' \
--header 'Content-Type: application/json' \
--data '{
"query": "query { epoch { referenceGasPrice } }"
}'

The response for the request above will look similarly to the following:

// omitted for brevity
x-sui-rpc-version: 0.1.0
{
"data": {
"epoch": {
"referenceGasPrice": "750"
}
},
"extensions": {
"usage": {
"nodes": 2,
"depth": 2,
"variables": 0,
"fragments": 0,
"query_payload": 37
}
}
}

Working with variables

Variables are a powerful way for passing different object IDs, Digests, Sui addresses, and other kinds of data for full flexibility. The following is an example for querying the reference gas price for epoch 100, by passing the epoch as a variable.

info

When working with the online GraphQL IDE, paste the variables' values in the Variables pane on the bottom left of the window, without the variables keyword. When not using variables, these need to be removed from the query.

A variable is declared and referred to using the $ symbol and its type (in this example Int) must be specified. Note that variables must be declared in the root query.

query ($epochID: Int) {
epoch(id: $epochID) {
referenceGasPrice
}
}

where the variable is:

{
"epochID": 100
}

Multiple data in one query

The previous RPC service required multiple queries for more complex data retrieval. Now, with GraphQL, you can specify the data you need in one single query.

For example, the following query retrieves the first 20 transaction blocks (along with the digest, the sender's address, the gas object used to pay for the transaction, the gas price, and the gas budget) after a specific transaction block at epoch 97. In the previous RPC, this would have required multiple API calls.

# Fetch the first 20 transactions after 231220100 for epoch 97
query {
epoch(id:97) {
transactionBlocks(first: 20, after:"231220100") {
pageInfo {
hasNextPage
endCursor
}
edges {
cursor
node {
digest
sender {
address
}
effects {
gasEffects {
gasObject {
address
}
}
}
gasInput {
gasPrice
gasBudget
}
}
}
}
}
}
info

By default, the number of results is limited to 50 items. To learn more about how GraphQL works with pagination, check out the official documentation and our following section on pagination.

Pagination

Sui GraphQL RPC limits the number of items that are returned in a request. The default page limit size is set to 50 items. If there are more items requested than the max default page limit, use cursors to navigate between pages. A cursor refers to a specific position in the dataset. To access the start and end cursors of a page, use the pageInfo field that exposes the cursor data and two additional fields indicating if there is a previous or next page. For example, if we want to get the checkpoints data:

query {
checkpoints {
pageInfo {
hasPreviousPage
hasNextPage
startCursor
endCursor
}
}
}

The query's result is:

{
"data": {
"checkpoints": {
"pageInfo": {
"hasPreviousPage": false,
"hasNextPage": true,
"startCursor": "0",
"endCursor": "49"
}
}
}
}

The pageInfo.startCursor and pageInfo.endCursor indicate the index of the first and last item in the response. You can use pageInfo.hasNextPage to determine if there is a next page, and then use the endCursor's value and pass it to the after filter in the connection to traverse the next set of elements:

query {
checkpoints(after: "49") {
[...]
}
info

When using pagination filters, you can only specify first or last, but not both.

Fragments

Fragments are reusable units that can be included in the queries as needed. The official docs contain more information about fragments. The following is an example of how fragments are used for querying a dynamic field of an owner.

query DynamicField {
object(
address: "0xb57fba584a700a5bcb40991e1b2e6bf68b0f3896d767a0da92e69de73de226ac"
) {
dynamicField(
name: {
type: "0x2::kiosk::Listing",
bcs: "NLArx1UJguOUYmXgNG8Pv8KbKXLjWtCi6i0Yeq1VhfwA",
}
) {
...DynamicFieldSelect
}
}
}

fragment DynamicFieldSelect on DynamicField {
name {
...DynamicFieldNameSelection
}
value {
...DynamicFieldValueSelection
}
}

fragment DynamicFieldNameSelection on MoveValue {
type {
repr
}
data
bcs
}

fragment DynamicFieldValueSelection on DynamicFieldValue {
... on MoveValue {
type {
repr
}
data
__typename
}
... on MoveObject {
hasPublicTransfer
contents {
type {
repr
}
data
}
__typename
}
}

Migrating guides

The following sections highlight the steps necessary for you to take to migrate your codebase to leverage the Sui GraphQL RPC.

From JSON RPC and examples

The former RPC API provided several individual endpoints to get specific data (for example, get_totalTransactionBlocks). While this can be achieved similarly with GraphQL, it is more powerful to determine the data you need in one query that involves multiple aspects (for example, transactions, balance, coins), execute that query, and get the results. This guide showcases how to (naively) use GraphQL instead of JSON RPC on a few original endpoints.

info

While a one-on-one mapping from JSON RPC to GraphQL is most likely possible, we recommend avoiding that route and to, instead, model your queries to leverage the full power of GraphQL.

Example 1: Get total transaction blocks

The goal is to get the total number of transaction blocks in the network.

{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_getTotalTransactionBlocks",
"params": []
}

Example 2: Get a specific transaction block

The goal is to get the transaction block by its digest.

{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_getTransactionBlock",
"params": [
"Hay2tj3GcDYcE3AMHrej5WDsHGPVAYsegcubixLUvXUF",
{
"showInput": true,
"showRawInput": false,
"showEffects": true,
"showEvents": true,
"showObjectChanges": false,
"showBalanceChanges": false
}
]
}

Example 3: Get coin objects owned by an address

The goal is to return all Coin<0x2::sui::SUI> objects an address owns.

query {
"jsonrpc": "2.0",
"id": 1,
"method": "suix_getCoins",
"params": [
"0x5094652429957619e6efa79a404a6714d1126e63f551f4b6c7fb76440f8118c9", //owner
"0x2::sui::SUI", //coin type
"0xe5c651321915b06c81838c2e370109b554a448a78d3a56220f798398dde66eab", //cursor
3 //limit
]
}