SuiGraphQLClient
Connect to Sui over GraphQL and write type-safe custom queries
SuiGraphQLClient talks to the Sui GraphQL API. It implements the same client API as
SuiGrpcClient, so anything on Querying data and
Signing and execution works here unchanged:
import { SuiGraphQLClient } from '@mysten/sui/graphql';
const client = new SuiGraphQLClient({
url: 'https://graphql.mainnet.sui.io/graphql',
network: 'mainnet',
});
const { object } = await client.getObject({
objectId: '0x...',
include: { content: true },
});Beyond that shared surface, the client can run any query the schema supports, typed from the schema itself. The rest of this page covers writing those queries; see the GraphQL reference for the schema.
The constructor takes:
| Option | Description |
|---|---|
url | GraphQL endpoint |
network | Network the endpoint serves, used for caching and MVR defaults |
headers | Extra headers sent with every request, such as an API key |
fetch | Custom fetch implementation |
queries | Named documents callable through execute |
mvr | Move Registry overrides |
Writing queries
Use query to run any GraphQL document against the endpoint:
import { graphql } from '@mysten/sui/graphql/schema';
const chainIdentifierQuery = graphql(`
query {
chainIdentifier
}
`);
const result = await client.query({ query: chainIdentifierQuery });
console.log(result.data?.chainIdentifier);Type safety
The graphql function is powered by gql.tada, which types results and
variables from the schema itself, with no code generation step and no hand-written result types.
Fields you did not select are not on the result type, and variables are checked against the query:
const getSuinsName = graphql(`
query getSuiName($address: SuiAddress!) {
address(address: $address) {
defaultNameRecord {
domain
}
}
}
`);
async function getDefaultSuinsName(address: string) {
const result = await client.query({
query: getSuinsName,
variables: { address },
});
return result.data?.address?.defaultNameRecord?.domain;
}Using typed documents with other clients
The graphql function returns document nodes implementing the
TypedDocumentNode standard, so the
same typed documents work with most GraphQL clients:
import { useQuery } from '@apollo/client';
import { graphql } from '@mysten/sui/graphql/schema';
const chainIdentifierQuery = graphql(`
query {
chainIdentifier
}
`);
function ChainIdentifier() {
// Result types flow through the other client's own hooks and methods
const { data } = useQuery(chainIdentifierQuery);
return <span>{data?.chainIdentifier}</span>;
}Handling errors
query returns { data, errors } rather than throwing on GraphQL errors, because a response can be
partially successful, where some fields resolve and others fail. Check errors before trusting
data:
const { data, errors } = await client.query({ query: chainIdentifierQuery });
if (errors?.length) {
throw new AggregateError(errors.map((error) => new Error(error.message)));
}A transport-level failure (a non-2xx response) throws SuiGraphQLRequestError instead.
Named queries
Pass a queries map when constructing the client and call them by name with execute. This keeps
query documents in one place instead of threading them through your call sites:
const client = new SuiGraphQLClient({
url: 'https://graphql.mainnet.sui.io/graphql',
network: 'mainnet',
queries: {
getSuinsName,
chainIdentifier: chainIdentifierQuery,
},
});
const result = await client.execute('getSuinsName', {
variables: { address: '0xabc...' },
});Results and variables stay typed from the document the name resolves to.
Reading your own writes
GraphQL reads an index that trails execution slightly, so a transaction executeTransaction has
already returned might not appear in a query for a moment. Use
waitForTransaction before reading back a
transaction's effects.