[][src]Trait juniper::GraphQLType

pub trait GraphQLType<S = DefaultScalarValue>: Sized where
    S: ScalarValue,
    &'b S: ScalarRefValue<'b>, 
{ type Context; type TypeInfo; fn name(info: &Self::TypeInfo) -> Option<&str>;
fn meta<'r>(
        info: &Self::TypeInfo,
        registry: &mut Registry<'r, S>
    ) -> MetaType<'r, S>
    where
        S: 'r
; fn resolve_field(
        &self,
        info: &Self::TypeInfo,
        field_name: &str,
        arguments: &Arguments<S>,
        executor: &Executor<Self::Context, S>
    ) -> ExecutionResult<S> { ... }
fn resolve_into_type(
        &self,
        info: &Self::TypeInfo,
        type_name: &str,
        selection_set: Option<&[Selection<S>]>,
        executor: &Executor<Self::Context, S>
    ) -> ExecutionResult<S> { ... }
fn concrete_type_name(
        &self,
        context: &Self::Context,
        info: &Self::TypeInfo
    ) -> String { ... }
fn resolve(
        &self,
        info: &Self::TypeInfo,
        selection_set: Option<&[Selection<S>]>,
        executor: &Executor<Self::Context, S>
    ) -> Value<S> { ... } }

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, Context,
              Arguments, Executor, ExecutionResult,
              DefaultScalarValue};
use juniper::meta::MetaType;

#[derive(Debug)]
struct User { id: String, name: String, friend_ids: Vec<String>  }
#[derive(Debug)]
struct Database { users: HashMap<String, User> }

impl Context for Database {}

impl GraphQLType for User
{
    type Context = Database;
    type TypeInfo = ();

    fn name(_: &()) -> Option<&'static str> {
        Some("User")
    }

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

        registry.build_object_type::<User>(&(), fields).into_meta()
    }

    fn resolve_field(
        &self,
        info: &(),
        field_name: &str,
        args: &Arguments,
        executor: &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 {
            // Because scalars are defined with another `Context` associated
            // type, you must use resolve_with_ctx here to make the executor
            // perform automatic type conversion of its argument.
            "id" => executor.resolve_with_ctx(info, &self.id),
            "name" => executor.resolve_with_ctx(info, &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(info,
                &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),
        }
    }
}

Associated Types

type Context

The expected context type for this GraphQL type

The context is threaded through query execution to all affected nodes, and can be used to hold common data, e.g. database connections or request session information.

type TypeInfo

Type that may carry additional schema information

This can be used to implement a schema that is partly dynamic, meaning that it can use information that is not known at compile time, for instance by reading it from a configuration file at start-up.

Loading content...

Required methods

fn name(info: &Self::TypeInfo) -> Option<&str>

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.

fn meta<'r>(
    info: &Self::TypeInfo,
    registry: &mut Registry<'r, S>
) -> MetaType<'r, S> where
    S: 'r, 

The meta type representing this GraphQL type.

Loading content...

Provided methods

fn resolve_field(
    &self,
    info: &Self::TypeInfo,
    field_name: &str,
    arguments: &Arguments<S>,
    executor: &Executor<Self::Context, S>
) -> ExecutionResult<S>

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.

fn resolve_into_type(
    &self,
    info: &Self::TypeInfo,
    type_name: &str,
    selection_set: Option<&[Selection<S>]>,
    executor: &Executor<Self::Context, S>
) -> ExecutionResult<S>

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.

fn concrete_type_name(
    &self,
    context: &Self::Context,
    info: &Self::TypeInfo
) -> String

Return the concrete type name for this instance/union.

The default implementation panics.

fn resolve(
    &self,
    info: &Self::TypeInfo,
    selection_set: Option<&[Selection<S>]>,
    executor: &Executor<Self::Context, S>
) -> Value<S>

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.

Loading content...

Implementations on Foreign Types

impl<S, T, CtxT> GraphQLType<S> for Option<T> where
    S: ScalarValue,
    T: GraphQLType<S, Context = CtxT>,
    &'b S: ScalarRefValue<'b>, 
[src]

type Context = CtxT

type TypeInfo = T::TypeInfo

impl<S, T, CtxT> GraphQLType<S> for Vec<T> where
    T: GraphQLType<S, Context = CtxT>,
    S: ScalarValue,
    &'b S: ScalarRefValue<'b>, 
[src]

type Context = CtxT

type TypeInfo = T::TypeInfo

impl<'a, S, T, CtxT> GraphQLType<S> for &'a [T] where
    S: ScalarValue,
    T: GraphQLType<S, Context = CtxT>,
    &'b S: ScalarRefValue<'b>, 
[src]

type Context = CtxT

type TypeInfo = T::TypeInfo

impl<S, T, CtxT> GraphQLType<S> for Box<T> where
    S: ScalarValue,
    T: GraphQLType<S, Context = CtxT>,
    &'b S: ScalarRefValue<'b>, 
[src]

type Context = CtxT

type TypeInfo = T::TypeInfo

impl<'a, S, T, CtxT> GraphQLType<S> for &'a T where
    S: ScalarValue,
    T: GraphQLType<S, Context = CtxT>,
    &'b S: ScalarRefValue<'b>, 
[src]

type Context = CtxT

type TypeInfo = T::TypeInfo

impl<S, T> GraphQLType<S> for Arc<T> where
    S: ScalarValue,
    T: GraphQLType<S>,
    &'b S: ScalarRefValue<'b>, 
[src]

type Context = T::Context

type TypeInfo = T::TypeInfo

impl<S> GraphQLType<S> for String where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<'a, S> GraphQLType<S> for &'a str where
    S: ScalarValue,
    &'b S: ScalarRefValue<'b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<S> GraphQLType<S> for bool where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<S> GraphQLType<S> for i32 where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<S> GraphQLType<S> for f64 where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<S> GraphQLType<S> for DateTime<FixedOffset> where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<S> GraphQLType<S> for DateTime<Utc> where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<S> GraphQLType<S> for NaiveDate where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<S> GraphQLType<S> for NaiveDateTime where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<S> GraphQLType<S> for Url where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<S> GraphQLType<S> for Uuid where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

Loading content...

Implementors

impl<'a, CtxT, S, QueryT, MutationT> GraphQLType<S> for RootNode<'a, QueryT, MutationT, S> where
    S: ScalarValue,
    QueryT: GraphQLType<S, Context = CtxT>,
    MutationT: GraphQLType<S, Context = CtxT>,
    &'b S: ScalarRefValue<'b>, 
[src]

type Context = CtxT

type TypeInfo = QueryT::TypeInfo

impl<'a, S> GraphQLType<S> for Argument<'a, S> where
    S: ScalarValue + 'a,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = SchemaType<'a, S>

type TypeInfo = ()

impl<'a, S> GraphQLType<S> for EnumValue where
    S: ScalarValue + 'a,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<'a, S> GraphQLType<S> for Field<'a, S> where
    S: ScalarValue + 'a,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = SchemaType<'a, S>

type TypeInfo = ()

impl<S> GraphQLType<S> for ID where
    S: ScalarValue,
    &'__b S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

impl<S, T> GraphQLType<S> for EmptyMutation<T> where
    S: ScalarValue,
    &'b S: ScalarRefValue<'b>, 
[src]

type Context = T

type TypeInfo = ()

impl<__S> GraphQLType<__S> for TypeKind where
    __S: ScalarValue,
    &'__b __S: ScalarRefValue<'__b>, 
[src]

type Context = ()

type TypeInfo = ()

Loading content...