Skip to main content

Crate sui_graphql_macros

Crate sui_graphql_macros 

Source
Expand description

Compile-time validated derive macro for deserializing Sui GraphQL responses.

GraphQL responses are deeply nested JSON. Rather than manually writing serde_json::Value traversal code (with .get(), .as_array(), null checks, etc.), the Response derive macro generates all of that from a declarative field path. Paths are validated against the Sui GraphQL schema at compile time, so typos and type mismatches are caught before your code ever runs.

For a complete client that uses this macro, see sui-graphql.

§Quick Start

use sui_graphql_macros::Response;

#[derive(Response)]
struct ObjectData {
    #[field(path = "object.address")]
    address: String,
    #[field(path = "object.version")]
    version: u64,
}
fn main() {}

The macro validates that object.address and object.version exist in the schema and that their types match at compile time. It then generates a from_value(serde_json::Value) -> Result<Self, String> method and a Deserialize implementation, so the struct can be used directly with serde_json::from_value or as a response type in GraphQL client calls.

§Path Syntax

Paths use dot-separated segments with optional suffixes:

SyntaxMeaningRust Type
fieldRequired fieldT
field?Nullable fieldOption<T>
field[]Required listVec<T>
field?[]Nullable listOption<Vec<T>>
field[]?List with nullable elementsVec<Option<T>>
field?[]?Nullable list, nullable elementsOption<Vec<Option<T>>>

Multiple ? markers between [] boundaries share one Option wrapper. Each ? controls null tolerance at that specific segment.

The macro enforces that path suffixes match the Rust type at compile time. For example, field? requires Option<T>, and field[] requires Vec<T>. A mismatch (e.g., field? with String or field with Option<String>) produces a compile error.

§Null Handling

use sui_graphql_macros::Response;

#[derive(Response)]
struct Example {
    // null at `object` → error, null at `address` → error
    #[field(path = "object.address")]
    strict: String,

    // null at `object` → Ok(None), null at `address` → Ok(None)
    #[field(path = "object?.address?")]
    flexible: Option<String>,

    // null at `object` → Ok(None), null at `address` → error
    #[field(path = "object?.address")]
    partial: Option<String>,
}
fn main() {}

§Lists

Use [] to mark list fields. The macro validates this matches the schema.

use sui_graphql_macros::Response;

#[derive(Response)]
struct CheckpointDigests {
    #[field(path = "checkpoints.nodes[].digest")]
    digests: Vec<String>,

    // Nullable list with nullable elements
    #[field(path = "checkpoints?.nodes?[]?.digest?")]
    maybe_digests: Option<Vec<Option<String>>>,
}
fn main() {}

§Aliases

Use alias:field when your GraphQL query uses aliases. The alias (before :) is the JSON key used for extraction, while the field name (after :) is validated against the schema. The alias itself is not schema-validated since it is user-defined in the query.

use sui_graphql_macros::Response;

#[derive(Response)]
struct EpochCheckpoints {
    // GraphQL alias "firstCp" maps to schema field "checkpoints"
    #[field(path = "epoch.firstCp:checkpoints.nodes[].sequenceNumber")]
    first_checkpoints: Vec<u64>,
}
fn main() {}

§Enums (GraphQL Unions)

Use #[response(root_type = "UnionType")] on enums with newtype variants:

#[derive(Response)]
#[response(root_type = "DynamicFieldValue")]
enum FieldValue {
    #[response(on = "MoveValue")]
    Value(MoveValueData),
    MoveObject(MoveObjectData), // `on` defaults to variant name
}

The macro dispatches on __typename in the JSON response.

§Attributes

AttributeLevelDescription
#[response(root_type = "Type")]struct/enumSchema type to validate against (default: "Query")
#[response(schema = "path")]struct/enumCustom schema file (relative to CARGO_MANIFEST_DIR)
#[field(path = "...")]fieldDot-separated path with optional ?/[]/alias
#[field(skip_schema_validation)]fieldSkip compile-time schema checks for this field
#[response(on = "TypeName")]variantGraphQL __typename to match (default: variant name)

Derive Macros§

Response
Derive macro for GraphQL response types with nested field extraction.