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:

  1. The easiest way, suitable for trivial cases, is to use the #[derive(GraphQLObject)] attribute on a struct, as described below.
  2. 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 nullable field is required, the most obvious way is to use Option. Or Nullable for distinguishing between explicit and implicit nulls.

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 and none (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-nullable Person objects.