Trait juniper::GraphQLType [] [src]

pub trait GraphQLType<CtxT>: Sized {
    fn name() -> Option<&'static str>;
    fn meta(registry: &mut Registry<CtxT>) -> MetaType;

    fn resolve_field(&self,
                 field_name: &str,
                 arguments: &Arguments,
                 executor: &mut Executor<CtxT>)
                 -> ExecutionResult { ... } fn resolve_into_type(&self,
                     type_name: &str,
                     selection_set: Option<Vec<Selection>>,
                     executor: &mut Executor<CtxT>)
                     -> ExecutionResult { ... } fn concrete_type_name(&self, context: &CtxT) -> String { ... } fn resolve(&self,
           selection_set: Option<Vec<Selection>>,
           executor: &mut Executor<CtxT>)
           -> Value { ... } }

Primary trait used to expose Rust types in a GraphQL schema

All of the convenience macros ultimately expand into an implementation of this trait for the given type. The macros remove duplicated definitions of fields and arguments, and add type checks on all resolve functions automatically. This can all be done manually.

GraphQLType provides some convenience methods for you, in the form of optional trait methods. The name and meta methods are mandatory, but other than that, it depends on what type you're exposing:

  • Scalars, enums, lists and non null wrappers only require resolve,
  • Interfaces and objects require resolve_field or resolve if you want to implement custom resolution logic (probably not),
  • Interfaces and unions require resolve_into_type and concrete_type_name.
  • Input objects do not require anything

Example

Manually deriving an object is straightforward but tedious. This is the equivalent of the User object as shown in the example in the documentation root:

use juniper::{GraphQLType, Registry, FieldResult,
              Arguments, Executor, ExecutionResult};
use juniper::meta::MetaType;

struct User { id: String, name: String, friend_ids: Vec<String>  }
struct Database { users: HashMap<String, User> }

impl GraphQLType<Database> for User {
    fn name() -> Option<&'static str> {
        Some("User")
    }

    fn meta(registry: &mut Registry<Database>) -> MetaType {
        // First, we need to define all fields and their types on this type.
        //
        // If need arguments, want to implement interfaces, or want to add
        // documentation strings, we can do it here.
        registry.build_object_type::<User>()(&[
                registry.field::<&String>("id"),
                registry.field::<&String>("name"),
                registry.field::<Vec<&User>>("friends"),
            ])
            .into_meta()
    }

    fn resolve_field(
        &self,
        field_name: &str,
        args: &Arguments,
        executor: &mut Executor<Database>
    )
        -> ExecutionResult
    {
        // Next, we need to match the queried field name. All arms of this
        // match statement return `ExecutionResult`, which makes it hard to
        // statically verify that the type you pass on to `executor.resolve`
        // actually matches the one that you defined in `meta()` above.
        let database = executor.context();
        match field_name {
            "id" => executor.resolve(&self.id),
            "name" => executor.resolve(&self.name),

            // You pass a vector of User objects to `executor.resolve`, and it
            // will determine which fields of the sub-objects to actually
            // resolve based on the query. The executor instance keeps track
            // of its current position in the query.
            "friends" => executor.resolve(
                &self.friend_ids.iter()
                    .filter_map(|id| database.users.get(id))
                    .collect::<Vec<_>>()
            ),

            // We can only reach this panic in two cases; either a mismatch
            // between the defined schema in `meta()` above, or a validation
            // in this library failed because of a bug.
            //
            // In either of those two cases, the only reasonable way out is
            // to panic the thread.
            _ => panic!("Field {} not found on type User", field_name),
        }
    }
}

Required Methods

The name of the GraphQL type to expose.

This function will be called multiple times during schema construction. It must not perform any calculation and always return the same value.

The meta type representing this GraphQL type.

Provided Methods

Resolve the value of a single field on this type.

The arguments object contain all specified arguments, with default values substituted for the ones not provided by the query.

The executor can be used to drive selections into sub-objects.

The default implementation panics through unimplemented!().

Resolve this interface or union into a concrete type

Try to resolve the current type into the type name provided. If the type matches, pass the instance along to executor.resolve.

The default implementation panics through unimplemented().

Return the concrete type name for this instance/union.

The default implementation panics through unimplemented().

Resolve the provided selection set against the current object.

For non-object types, the selection set will be None and the value of the object should simply be returned.

For objects, all fields in the selection set should be resolved.

The default implementation uses resolve_field to resolve all fields, including those through fragment expansion, for object types. For non-object types, this method panics through unimplemented!().

Implementors