sui_graphql/lib.rs
1//! GraphQL client for the [Sui] blockchain.
2//!
3//! [Sui]: https://sui.io
4//!
5//! This crate provides a typed GraphQL client for Sui's GraphQL API with
6//! automatic BCS deserialization and pagination support.
7//!
8//! # Quick Start
9//!
10//! ```no_run
11//! use sui_graphql::Client;
12//!
13//! #[tokio::main]
14//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
15//! let client = Client::new(Client::MAINNET)?;
16//!
17//! // Chain info
18//! let chain_id = client.chain_identifier().await?;
19//! println!("Chain: {chain_id}");
20//!
21//! // Fetch objects, transactions, checkpoints
22//! let obj = client.get_object("0x5".parse()?).await?;
23//! let tx = client.get_transaction("digest...").await?;
24//! let cp = client.get_checkpoint(None).await?; // latest
25//!
26//! Ok(())
27//! }
28//! ```
29//!
30//! # Streaming
31//!
32//! List methods return async streams with automatic pagination:
33//!
34//! ```no_run
35//! use futures::StreamExt;
36//! use std::pin::pin;
37//! use sui_graphql::Client;
38//! use sui_sdk_types::Address;
39//!
40//! #[tokio::main]
41//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
42//! let client = Client::new(Client::MAINNET)?;
43//! let owner: Address = "0x123...".parse()?;
44//!
45//! let mut stream = pin!(client.list_objects(owner));
46//! while let Some(obj) = stream.next().await {
47//! let obj = obj?;
48//! println!("Object version: {}", obj.version());
49//! }
50//! Ok(())
51//! }
52//! ```
53//!
54//! # Custom Queries
55//!
56//! For queries beyond the built-in methods, use [`Client::query`] with a
57//! response type that implements [`serde::de::DeserializeOwned`]. The
58//! [`sui-graphql-macros`] crate provides `graphql_query!` to validate the
59//! query string and `#[derive(Response)]` to generate the response
60//! deserialization code, both checked against the Sui GraphQL schema at
61//! compile time.
62//!
63//! [`sui-graphql-macros`]: https://docs.rs/sui-graphql-macros
64//!
65//! ```no_run
66//! use sui_graphql::Client;
67//! use sui_graphql_macros::Response;
68//! use sui_graphql_macros::graphql_query;
69//!
70//! // Define a response type with field paths into the GraphQL response JSON.
71//! // Paths are validated against the schema at compile time — typos like
72//! // "epoch.epochIdd" will produce a compile error with a "Did you mean?" suggestion.
73//! #[derive(Response)]
74//! struct MyResponse {
75//! #[field(path = "epoch.epochId")]
76//! epoch_id: u64,
77//! // Use `[]` to extract items from a list field
78//! #[field(path = "epoch.checkpoints.nodes[].digest")]
79//! checkpoint_digests: Vec<String>,
80//! // Use `?` to mark nullable fields — null returns Ok(None) instead of an error.
81//! // Without `?`, a null value at that segment is a runtime error.
82//! #[field(path = "epoch.referenceGasPrice?")]
83//! gas_price: Option<u64>,
84//! }
85//!
86//! #[tokio::main]
87//! async fn main() -> Result<(), sui_graphql::Error> {
88//! let client = Client::new(Client::MAINNET)?;
89//!
90//! // `graphql_query!` validates the query against the schema at compile time.
91//! const QUERY: &str = graphql_query!(
92//! "query($epochId: UInt53) {
93//! epoch(epochId: $epochId) {
94//! epochId
95//! checkpoints { nodes { digest } }
96//! referenceGasPrice
97//! }
98//! }"
99//! );
100//! let variables = serde_json::json!({ "epochId": 100 });
101//!
102//! let response = client.query::<MyResponse>(QUERY, variables).await?;
103//!
104//! // GraphQL supports partial success — data and errors can coexist
105//! for err in response.errors() {
106//! eprintln!("GraphQL error: {}", err.message());
107//! }
108//! if let Some(data) = response.data() {
109//! println!("Epoch: {}", data.epoch_id);
110//! println!("Checkpoints: {:?}", data.checkpoint_digests);
111//! println!("Gas price: {:?}", data.gas_price);
112//! }
113//! Ok(())
114//! }
115//! ```
116//!
117//! For the full path syntax reference (`?`, `[]`, aliases, enums), see the
118//! [`sui-graphql-macros` documentation](https://docs.rs/sui-graphql-macros).
119//!
120//! See [`Client`] for the full list of available methods.
121
122mod bcs;
123mod client;
124mod error;
125mod move_value;
126mod pagination;
127mod response;
128pub mod scalars;
129
130/// Re-export of [`reqwest::header`] so callers using
131/// [`Client::with_headers`](crate::Client::with_headers) /
132/// [`Client::extend_headers`](crate::Client::extend_headers) don't need to add
133/// `reqwest` as a direct dependency.
134pub use reqwest::header;
135
136pub use bcs::Bcs;
137pub use bcs::BcsBytes;
138pub use client::Client;
139pub use client::chain::Epoch;
140pub use client::checkpoints::CheckpointResponse;
141pub use client::coins::Balance;
142pub use client::dynamic_fields::DynamicField;
143pub use client::dynamic_fields::DynamicFieldRequest;
144pub use client::dynamic_fields::DynamicFieldValue;
145pub use client::dynamic_fields::DynamicFieldsRequest;
146pub use client::dynamic_fields::Format;
147pub use client::execution::ExecutionResult;
148pub use client::transactions::TransactionResponse;
149pub use error::Error;
150pub use error::GraphQLError;
151pub use error::Location;
152pub use error::PathFragment;
153pub use move_value::MoveObject;
154pub use move_value::MoveValue;
155pub use pagination::Page;
156pub use pagination::PageInfo;
157pub use pagination::paginate;
158pub use pagination::paginate_backward;
159pub use response::Response;
160pub use sui_graphql_macros::graphql_query;