Launching the Beta GraphQL RPC service

We’re happy to announce the launch of a Beta version of the Sui GraphQL RPC service, as part of our ongoing efforts to provide the best web3 infrastructure and developer experience.
This Beta version of the Sui GraphQL RPC service is a READ-ONLY service consisting of a snapshot of Sui mainnet,
which has data available up to epoch 196 and checkpoint 16564261. Please note that the mainnet data is frozen and it will not be updated. A testnet service is planned for a later date and we will update this post when it gets launched.

Getting Started

Go to https://graphql-beta.mainnet.sui.io and try the new API out. The online IDE provides an interactive experience by offering auto-completion (use Ctrl+Space) and in-built documentation. The Sui repository has documented examples that are generated from GraphQL query files that you can reuse. Note that any addresses or object IDs in the examples correspond to the mainnet data.

You can find the GraphQL schema by querying the /schema endpoint (e.g., https://graphql-beta.mainnet.sui.io/schema) or using the playground IDE.

Upcoming RPC 2.0

If you’re interested in the technical details, the timelines around RPC 2.0, the overall architecture and why a new RPC, check out this GitHub Issue: RPC 2.0 · Issue #13700 · MystenLabs/sui · GitHub

Feedback

We welcome feedback that you have, particularly about the schema, so please post it in this thread!

Disclaimer & Limitations

Please note that this service is offered as is, without a SLA, and it is not intended nor recommended for production ready applications. Its main purpose is to allow developers to discover the offerings of the upcoming RPC 2.0 service.

The endpoint is rate-limited to avoid congestion and misuse (this service is not intended for production) and it does have some limits on the complexity of the queries one can make. Please use this query to find the current rate limits on the GraphQL queries:

query {
    serviceConfig {
        maxQueryDepth
        maxQueryNodes
        maxDbQueryCost
        maxQueryVariables
        maxQueryFragments
        requestTimeoutMs
    }
}

By default, there is a query timeout of 40s. If the time limit is exceeded, the query is stopped and an error is returned.

As this is only a beta version, there are a few unsupported features and/or limitations:

  • There are no performance optimizations, thus some queries may be slower than expected
  • Subscriptions are not supported
  • Executing transactions and other information on-chain is not possible - the beta release is a READ-ONLY service
  • Queries requesting stake related information might be a bit slower or fail the first time, depending on an internal cache. If it fails, try again after a couple of minutes.

The following parts of the draft schema are are not available at the time of writing (2023-10-31), either because they are under development or out of scope for this beta. For a list of supported features, please consult the documentation in the online IDE:

Top-level

  • Query.availableRange
  • Query.coinMetadata

TransactionBlock

  • kind is missing structured data for certain kinds of transaction

TransactionBlockEffects

  • objectReads

ObjectOwner

Object Owner refers to any type (Address, Owner, Object) that could own other objects. The following fields are not supported on these types:

  • nameServiceConnection
  • dynamicField
  • dynamicFieldConnection

Validator

  • apy

Filters

All filters do not support combination (any, all, not) filters, and the following specific filters are to be implemented:

  • ObjectFilter: Filtering by package, module and type, and filtering by object key (ID and version).
  • EventFilter: Filtering by event package, module or type.
  • TransactionBlockFilter: Filtering by the address that paid for the transaction, the start or end time.

Executing Transactions

Execution is unsupported and out of scope for this beta.

  • Query.dryRunTransactionBlock
  • Mutation.executeTransactionBlock

Subscriptions

Subscription APIs are unsupported and out of scope for this beta.

  • Subscription.events
  • Subscription.transactions
9 Likes

Few Qs:

  1. Where/when will we be able to get/query the Sui graphql version?
  2. Will there be a generic well known error structure?

I may have more. So far, it does what you said it would do and haven’t run into any issues but haven’t gone deep yet.

3 Likes

Hi @fastfrank, firstly, thanks for trying out the beta!

  1. Where/when will we be able to get/query the Sui graphql version?

The version of the service that served your request is always available in the response header (X-Sui-RPC-Version), and you specify the version you care to use with the same header, but in the request. When you specify it you can only request a specific major.minor version, and in the response, you will also be told which patch version.

  1. Will there be a generic well known error structure?

We do have a very high level error structure. It boils down to an error message and a code. For example, here’s an error response from me sending a request with a malformed version header:

{
  "data": null,
  "errors": [
    {
      "message": "Failed to parse x-sui-rpc-version: 'xyz' not a valid <YEAR>.<MONTH> version.",
      "extensions": {
        "code": "BAD_REQUEST"
      }
    }
  ]
}

The codes we have so far are:

  • BAD_USER_INPUT: Some issue with the parameters to the GraphQL query – this is usually the user’s fault.
  • BAD_REQUEST: Some other issue with the input to the service, (failed to parse the GraphQL altogether, field doesn’t exist, etc). Often this is something that the SDK could catch before sending the request.
  • INTERNAL_SERVER_ERROR: Our fault, this is a bug in the service which we’d like to hear about (the one way you can trigger this today in the beta is by requesting an unsupported version – because usually the service will be behind a load-balancer that will route requests by version but the beta is not set up this way).

We may add more of these, for example hitting a limit is usually cause for BAD_REQUEST but we may want to split this out into requests that are bad because of the content of the request (too many nodes, too deep, etc) and requests that are bad because of some time sensitive factor (rate limits, timeouts, etc).

If you have any thoughts or feedback on what kind of error structure would be helpful, we’d love to hear that too, cc @willyang who’s looking into this area.

3 Likes

Hi @amnn,

Ok, both your responses are welcomed. I am fine with the version answer.
As far as the Error structure it is always a balance between simple and informative on one end and the locus of the issues, how deep in the processing when the error may occur and the combinatorial aspects at the other end.

Having said that :slight_smile: , I think what you have is fine as long as the CODES are expressive enough.

Thanks!

2 Likes

Question:
On Address/coinConnection there is a type argument (takes a string), trying to understand what that applies to.

I have a query to get to the coins of an address vis-a-vis coinConnection.content.node (etc.) which produces coins array in the data. However; adding the `type: “0x2::coin::Coin<0x2::sui::SUI>” cause the query to retrun empy.

Frank

2 Likes

The type argument is like a filter, it specifies which coins you’d like to see.
It does return empty because it only needs the inner type (0x2::sui::SUI)
Try with 0x2::sui::SUI and let me know if it works.

Here’s a working example with an address from mainnet.

{
  address(
    address: "0x27500c5026048b838358acb14498ab5b90d4e78a9559f280145dbf7a8dbc17bb"
  ) {
    coinConnection(type: "0x2::sui::SUI") {
      nodes {
        id
      }
    }
  }
}
2 Likes

Worked like a charm!

Thanks

2 Likes

Just FYI, I added comments for the coin_connection stuff which should be reflected in the docs to avoid getting the user confused. However, not sure when these changes will be deployed to the mainnet service that’s running now, but hopefully at some point.

1 Like

Good to know.

Is there a cadence planed or notification when the mainnet? Also, will there be deployment for testnet as part of this phase or are devnet and testnet planned for when you are closer to releasing?

1 Like

The release cadence for RPC 1.5 will be ad-hoc, as we bunch up significant new features to share with folks to try out. This does mean that things will be a little bit bumpy (breaking changes etc), but we are trading off stability for velocity at the moment.

When we do make a new release of 1.5, we will share a summary of the user-facing changes in this thread.

Of course, once we hit our next milestone (the RPC 2.0 MVP launch), this will change (no breaking changes outside of major releases, which happen quarterly, and 6 months of support for each major version from the Mysten-operated RPC services).

We are working on a testnet release, in fact it is available at graphql-beta.testnet.sui.io, but it is still catching up, so we have not formally announced it. As of today, it has data until 21st September (inclusive).

1 Like

Great, looking forward to the next mainnet beta and the new features you are ‘bunching’ up for deployment.

1 Like

Hi everyone, the upgrade to GraphQL Beta is now live for both mainnet and testnet via https://graphql-beta.mainnet.sui.io and https://graphql-beta.testnet.sui.io respectively.

Thank you to everyone who tried out the service and submitted feedback to help us improve, please keep it coming!

Release Notes

This release adds support for querying dynamic fields, CoinMetadata, timestamps for TransactionBlocks, coinType for BalanceChanges and a top-level coinConnection, adds partial support for querying fields on modules in Move packages, renames Stake to StakedSui, and addresses a number of bugs.

Please see the schema diff and the changelog to follow for full details.

Changelog

  • #14382, #14670: Fixes a bug where some outputs did not canonicalize types by normalizing address lengths to a 64 character lowercase hex representation with a leading ‘0x’.
    BUGFIX
  • #14960: Adds ability to customise the title of GraphiQL IDE.
  • #14965: Filters that expect a Coin Type accept non-canonicalized types (with short addresses).

Address

  • #14896: Fixes a bug where Address.objectConnection returns objects not owned by that address.
    BUGFIX

BalanceChange

  • #14734: Implements coinType so that we know the coin type of the balance that was changed in transaction effects.

CoinMetadata

  • #14818: Implements the CoinMetadata type, MoveObject.asCoinMetadata to downcast an existing object, and Query.coinMetadata to fetch them.

MoveModule

  • #14930: Implements the following fields: moduleId, bytes, disassembly.
  • #14935: Implements friendConnection.

Owner

  • #14687: Implements dynamicFieldConnection for iterating over all an object’s dynamic fields and dynamic object fields, in a paginated query.
  • #14714: Implements dynamicField and dynamicObjectField for fetching dynamic fields and dynamic object fields from an object.
  • #14804: Fixes a bug where not supplying a coin type for coinConnection queries defaulted to supplying all coins, rather than the existing JSON-RPC behaviour of supplying gas coins.
    BUGFIX

Query

  • #14954: Adds a top-level coinConnection.

ServiceConfig

  • #14715, #14792: Removes limits on number of fragments and variables, in favor of a limit on overall request payload size.
    Breaking Change
  • #14949: Max page size becomes a configurable parameter, and defaults to 50.
    Breaking Change

StakedSui

  • #14816: Renames Stake to StakedSui to match the name of its corresponding Move type.
    Breaking Change

TransactionBlock

  • #14688: Fixes a bug where checkpoint always fetched the latest checkpoint, rather than the checkpoint the transaction was originally from.
    BUGFIX
  • #14694: Implements timestamp field.

TransactionBlockKind

  • #14743: Introduces a new system transaction kind (RandomnessStateUpdate) corresponding to an upcoming change in the protocol.
3 Likes