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