Objects
GraphQL objects represent a list of named fields, each of which yield a value of a specific type.
When declaring a GraphQL schema, most of the time we deal with GraphQL objects, because they are the only place where we actually define the behavior once schema gets executed.
There are two ways to define a GraphQL object in Juniper:
- The easiest way, suitable for trivial cases, is to use the
#[derive(GraphQLObject)]
attribute on a struct, as described below. - The other way, using the
#[graphql_object]
attribute, is described in the "Complex fields" chapter.
Trivial
While any type in Rust can be exposed as a GraphQL object, the most common one is a struct:
extern crate juniper; use juniper::GraphQLObject; #[derive(GraphQLObject)] struct Person { name: String, age: i32, } fn main() {}
This creates a GraphQL object type called Person
, with two fields: name
of type String!
, and age
of type Int!
. Because of Rust's type system, everything is exported as non-null
by default.
TIP: If a
null
able field is required, the most obvious way is to useOption
. OrNullable
for distinguishing between explicit and implicitnull
s.
Documentation
We should take advantage of the fact that GraphQL is self-documenting and add descriptions to the defined GraphQL object type and its fields. Juniper will automatically use associated Rust doc comments as GraphQL descriptions:
extern crate juniper; use juniper::GraphQLObject; /// Information about a person. #[derive(GraphQLObject)] struct Person { /// The person's full name, including both first and last names. name: String, /// The person's age in years, rounded down. age: i32, } fn main() {}
If using Rust doc comments is not desired (for example, when we want to keep Rust API docs and GraphQL schema descriptions different), the #[graphql(description = "...")]
attribute can be used instead, which takes precedence over Rust doc comments:
extern crate juniper; use juniper::GraphQLObject; /// This doc comment is visible only in Rust API docs. #[derive(GraphQLObject)] #[graphql(description = "This description is visible only in GraphQL schema.")] struct Person { /// This doc comment is visible only in Rust API docs. #[graphql(desc = "This description is visible only in GraphQL schema.")] // ^^^^ shortcut for a `description` argument name: String, /// This doc comment is visible in both Rust API docs and GraphQL schema /// descriptions. age: i32, } fn main() {}
Renaming
By default, struct fields are converted from Rust's standard snake_case
naming convention into GraphQL's camelCase
convention:
extern crate juniper; use juniper::GraphQLObject; #[derive(GraphQLObject)] struct Person { first_name: String, // exposed as `firstName` in GraphQL schema last_name: String, // exposed as `lastName` in GraphQL schema } fn main() {}
We can override the name by using the #[graphql(name = "...")]
attribute:
extern crate juniper; use juniper::GraphQLObject; #[derive(GraphQLObject)] #[graphql(name = "WebPerson")] // now exposed as `WebPerson` in GraphQL schema struct Person { name: String, age: i32, #[graphql(name = "websiteURL")] website_url: Option<String>, // now exposed as `websiteURL` in GraphQL schema } fn main() {}
Or provide a different renaming policy for all the struct fields:
extern crate juniper; use juniper::GraphQLObject; #[derive(GraphQLObject)] #[graphql(rename_all = "none")] // disables any renaming struct Person { name: String, age: i32, website_url: Option<String>, // exposed as `website_url` in GraphQL schema } fn main() {}
TIP: Supported policies are:
SCREAMING_SNAKE_CASE
,camelCase
andnone
(disables any renaming).
Deprecation
To deprecate a GraphQL object field, either the #[graphql(deprecated = "...")]
attribute, or Rust's #[deprecated]
attribute, should be used:
extern crate juniper; use juniper::GraphQLObject; #[derive(GraphQLObject)] struct Person { name: String, age: i32, #[graphql(deprecated = "Please use the `name` field instead.")] first_name: String, #[deprecated(note = "Please use the `name` field instead.")] last_name: String, } fn main() {}
NOTE: Only GraphQL object/interface fields and GraphQL enum values can be deprecated.
Ignoring
By default, all struct fields are included into the generated GraphQL object type. To prevent inclusion of a specific field annotate it with the #[graphql(ignore)]
attribute:
#![allow(dead_code)] extern crate juniper; use juniper::GraphQLObject; #[derive(GraphQLObject)] struct Person { name: String, age: i32, #[graphql(ignore)] password_hash: String, // cannot be queried from GraphQL #[graphql(skip)] // ^^^^ alternative naming, up to your preference is_banned: bool, // cannot be queried from GraphQL } fn main() {}
TIP: See more available features in the API docs of the
#[derive(GraphQLObject)]
attribute.
Relationships
GraphQL object fields can be of any GraphQL type, except input objects.
Let's see what it means to build relationships between objects:
extern crate juniper; use juniper::GraphQLObject; #[derive(GraphQLObject)] struct Person { name: String, age: i32, } #[derive(GraphQLObject)] struct House { address: Option<String>, // converted into `String` (`null`able) inhabitants: Vec<Person>, // converted into `[Person!]!` } fn main() {}
Because Person
is a valid GraphQL type, we can have a Vec<Person>
in a struct, and it'll be automatically converted into a list of non-null
able Person
objects.