Complex fields

Using a plain Rust struct for representing a GraphQL object is easy and trivial but does not cover every case. What if we need to express something non-trivial as a GraphQL field, such as:

To support these more complicated use cases, we need a way to define a GraphQL field as a function. In Juniper this is achievable by placing the #[graphql_object] attribute on an impl block, which turns its methods into GraphQL fields:

extern crate juniper;
use juniper::{graphql_object, GraphQLObject};

#[derive(GraphQLObject)]
struct Person {
    name: String,
    age: i32,
}

struct House {
    inhabitants: Vec<Person>,
}

// Defines the `House` GraphQL object.
#[graphql_object]
impl House {
    // Creates the field `inhabitantWithName(name: String!)`, 
    // returning a `null`able `Person`.
    fn inhabitant_with_name(&self, name: String) -> Option<&Person> {
        self.inhabitants.iter().find(|p| p.name == name)
    }
}

fn main() {}

NOTE: To access global data such as database connections or authentication information, a context is used. To learn more about this, see the "Context" chapter.

Default arguments

Though Rust doesn't have the notion of default arguments, GraphQL arguments are able to have default values. These default values are used when a GraphQL operation doesn't specify the argument explicitly. In Juniper, defining a default value for a GraphQL argument is enabled by the #[graphql(default)] attribute:

extern crate juniper;
use juniper::graphql_object;

struct Person;

#[graphql_object]
impl Person {
    fn field1(
        // Default value can be any valid Rust expression, including a function
        // call, etc.
        #[graphql(default = true)]
        arg1: bool,
        // If default expression is not specified, then the `Default::default()` 
        // value is used.
        #[graphql(default)]
        arg2: i32,
    ) -> String {
        format!("{arg1} {arg2}")
    }
}

fn main() {}

Renaming

Like with the #[derive(GraphQLObject)] attribute on structs, field names are converted from Rust's standard snake_case naming convention into GraphQL's camelCase convention.

We can override the name by using the #[graphql(name = "...")] attribute:

extern crate juniper;
use juniper::graphql_object;

struct Person;

#[graphql_object]
#[graphql(name = "PersonObject")]
impl Person { // exposed as `PersonObject` in GraphQL schema
    #[graphql(name = "myCustomFieldName")]
    fn renamed_field( // exposed as `myCustomFieldName` in GraphQL schema
        #[graphql(name = "myArgument")]
        renamed_argument: bool, // exposed as `myArgument` in GraphQL schema
    ) -> bool {
        renamed_argument
    }
}

fn main() {}

Or provide a different renaming policy for all the defined fields:

extern crate juniper;
use juniper::graphql_object;

struct Person;

#[graphql_object]
#[graphql(rename_all = "none")] // disables any renaming
impl Person {
    fn renamed_field( // exposed as `renamed_field` in GraphQL schema
        renamed_argument: bool, // exposed as `renamed_argument` in GraphQL schema
    ) -> bool {
        renamed_argument
    }
}

fn main() {}

TIP: Supported policies are: SCREAMING_SNAKE_CASE, camelCase and none (disables any renaming).

Documentation and deprecation

Similarly, GraphQL fields may also be documented and deprecated via #[graphql(description = "...")] and #[graphql(deprecated = "...")]/#[deprecated] attributes:

extern crate juniper;
use juniper::graphql_object;

struct Person;

/// This doc comment is visible only in Rust API docs.
#[graphql_object]
#[graphql(description = "This description overwrites the one from doc comment.")]
impl Person {
    /// This doc comment is visible only in Rust API docs.
    #[graphql(description = "This description is visible only in GraphQL schema.")]
    fn empty() -> &'static str {
        ""
    }
    
    #[graphql(desc = "This description is visible only in GraphQL schema.")]
    //        ^^^^ shortcut for a `description` argument
    fn field(
        #[graphql(desc = "This description is visible only in GraphQL schema.")]
        arg: bool,
    ) -> bool {
        arg
    }

    /// This doc comment is visible in both Rust API docs and GraphQL schema 
    /// descriptions.
    #[graphql(deprecated = "Just because.")]
    fn deprecated_graphql() -> bool {
        true
    }
    
    // Standard Rust's `#[deprecated]` attribute works too!
    #[deprecated(note = "Reason is optional, btw!")]
    fn deprecated_standard() -> bool { // has no description in GraphQL schema
        false
    }
}

fn main() {}

NOTE: Only GraphQL object/interface fields and GraphQL enum values can be deprecated.

Ignoring

By default, all methods of an impl block are exposed as GraphQL fields. If a method should not be exposed as a GraphQL field, it should be defined in a separate impl block or marked with the #[graphql(ignore)] attribute:

#![allow(dead_code)]
extern crate juniper;
use juniper::graphql_object;

struct Person {
    name: String,
    age: i32,
}

#[graphql_object]
impl Person {
    fn name(&self) -> &str {
        self.name.as_str()
    }

    fn age(&self) -> i32 {
        self.age
    }

    #[graphql(ignore)]
    pub fn hidden_from_graphql(&self) {
        // whatever goes...
    }

    #[graphql(skip)]
    //        ^^^^ alternative naming, up to your preference
    pub fn also_hidden_from_graphql(&self) {
        // whatever goes...
    }
}

impl Person {
    pub fn not_even_considered_for_graphql(&self) {
        // whatever goes...
    }
}

fn main() {}

TIP: See more available features in the API docs of the #[graphql_object] attribute.