Skip to main content

Crate sui_graphql_macros

Crate sui_graphql_macros 

Source
Expand description

Compile-time validated macros for the Sui GraphQL API.

Two macros, both validated against the embedded Sui GraphQL schema:

  • Response — derive macro for response types. Generates JSON deserialization from declarative field paths, catching unknown fields and type mismatches before your code runs.
  • graphql_query! — function-style macro for query/mutation strings. Validates the source against the schema, so unknown fields, undefined variables, and bad arguments fail to compile.

For a complete client that uses both, 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, a borrowed extract(&serde_json::Value) -> Result<Self, String> variant, 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() {}

§Flattened Responses

Use #[field(flatten)] to populate a field by passing the complete response value to that field type’s borrowed extract method. This allows response types that read from the same root value to be composed without cloning it or repeating their field paths. flatten cannot be combined with path.

use sui_graphql_macros::Response;

#[derive(Response)]
struct ChainInfo {
    #[field(path = "chainIdentifier")]
    chain_id: String,
}

#[derive(Response)]
struct ResponseData {
    #[field(flatten)]
    chain: ChainInfo,
}
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(flatten)]fieldPopulate by calling the field type’s extract with the complete response value
#[field(skip_schema_validation)]fieldSkip compile-time schema checks for this field
#[response(on = "TypeName")]variantGraphQL __typename to match (default: variant name)

Macros§

graphql_query
Validate a GraphQL query or mutation against the embedded Sui schema at compile time and return it as a &'static str.

Derive Macros§

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