Objects
Define GraphQL object types from your application's data.
A Rust type is the backing model. #[derive(Object)] ties it to a GraphQL name and gives the
executor a way to recognise values of that type.
Define an object type
The Rust type name is the GraphQL name. Override it with an attribute:
A doc comment becomes the description unless #[graphql(description = "...")] is supplied.
Fields are not derived. Declare them on the schema builder, where the resolver, arguments and access rules live:
The model and the GraphQL API can have different shapes. heightInMeters is exposed as height;
birthday is available to resolvers but not exposed as a field. Computed fields do not need new
properties on the model.
expose! supports nested properties:
Add a query
Query the object:
Refs and runtime names
Rust already has a typed reference to the model: the type itself. For names that are not known until the application runs — Relay connections and mutation payloads are the usual cases — use an object reference:
object_ref creates or reopens the named type. implement adds fields, exactly like object.
The same name and model merge; a different Rust model claiming the name is a build error.
field_ref takes list and nullability wrappers from the resolver's return type and replaces only
the named type. See runtime-named types.
Splitting a definition across modules
object reopens an existing object, so a type can be declared in several modules or files.
Descriptions, interfaces and the generated is_type_of check are preserved. A field name
declared twice is still a build error.
interface / interface_fields, query / query_fields, mutation / mutation_fields and
subscription / subscription_fields behave the same way. Root declarations append; the
*_fields spelling just states the intent.
How values travel
A resolver returns the Rust model. gurafi converts it to gql::Value::External, so the
executor can pass a borrowed &Giraffe to every child resolver without cloning the object. The
derived is_type_of check recognises that model when an abstract field needs its concrete type.
This is why a model type is the first argument of every object resolver:
The borrow lasts for the resolver call. If a resolver needs to return an owned value, return a clone or construct a new model.
Required trait bounds
#[derive(Object)] requires the type to be Send + Sync + 'static. Derive Clone if resolvers
or loaders need to return copies. For types that are not Clone, return references from
resolvers where possible or construct the value from data.
Objects are registered by name in gql. A field may return a type registered later; build()
reports a referenced type that was never registered, with the missing name and the fix.
Next
- Fields covers resolver shapes, lists and nullability.
- Interfaces and unions add abstract output types.
- Runtime-named types covers Relay-style names.
- Raw values covers resolving a whole object from a value you already have.
