Crate juniper [−] [src]
GraphQL
GraphQL is a data query language developed by Facebook intended to serve mobile and web application frontends. A server provides a schema, containing types and fields that applications can query. Queries are hierarchical, composable, and statically typed. Schemas are introspective, which lets clients statically verify their queries against a server without actually executing them.
This library provides data types and traits to expose Rust types in a GraphQL schema, as well as an optional integration into the Iron framework and Rocket. It tries to keep the number of dynamic operations to a minimum, and give you as the schema developer the control of the query execution path.
Juniper only depends on serde
and serde_derive
by default, making it
lightweight and easy to drop into any project. If you enable any of the
optional framework integrations, it will naturally depend on those frameworks
too.
Exposing data types
The GraphQLType
trait is the primary interface towards application developers.
By deriving this trait, you can expose your types as either objects, enums,
interfaces, unions, or scalars.
However, due to the dynamic nature of GraphQL's type system, deriving this trait
manually is a bit tedious, especially in order to do it in a fully type safe
manner. To help with this task, this library provides a couple of macros; the
most common one being graphql_object!
. Use this macro to expose your already
existing object types as GraphQL objects:
#[macro_use] extern crate juniper; use juniper::{Context, FieldResult}; struct User { id: String, name: String, friend_ids: Vec<String> } struct QueryRoot; struct Database { users: HashMap<String, User> } impl Context for Database {} // GraphQL objects can access a "context object" during execution. Use this // object to provide e.g. database access to the field accessors. This object // must implement the `Context` trait. If you don't need a context, use the // empty tuple `()` to indicate this. // // In this example, we use the Database struct as our context. graphql_object!(User: Database |&self| { // Expose a simple field as a GraphQL string. field id() -> &String { &self.id } field name() -> &String { &self.name } // FieldResult<T> is an alias for Result<T, String> - simply return // a string from this method and it will be correctly inserted into // the execution response. field secret() -> FieldResult<&String> { Err("Can't touch this".to_owned()) } // Field accessors can optionally take an "executor" as their first // argument. This object can help guide query execution and provides // access to the context instance. // // In this example, the context is used to convert the friend_ids array // into actual User objects. field friends(&executor) -> Vec<&User> { self.friend_ids.iter() .filter_map(|id| executor.context().users.get(id)) .collect() } }); // The context object is passed down to all referenced types - all your exposed // types need to have the same context type. graphql_object!(QueryRoot: Database |&self| { // Arguments work just like they do on functions. field user(&executor, id: String) -> Option<&User> { executor.context().users.get(&id) } });
Adding per type, field, and argument documentation is possible directly from
this macro. For more in-depth information on how to expose fields and types, see
the graphql_object!
macro.
Integrating with Iron
The most obvious usecase is to expose the GraphQL schema over an HTTP endpoint. To support this, the library provides optional and customizable handlers for both Iron and Rocket.
For example, continuing from the schema created above and using Iron to expose the schema on an HTTP endpoint supporting both GET and POST requests:
extern crate iron; use iron::prelude::*; use juniper::iron_handlers::GraphQLHandler; use juniper::{Context, EmptyMutation}; // This function is executed for every request. Here, we would realistically // provide a database connection or similar. For this example, we'll be // creating the database from scratch. fn context_factory(_: &mut Request) -> Database { Database { users: vec![ ( "1000".to_owned(), User { id: "1000".to_owned(), name: "Robin".to_owned(), friend_ids: vec!["1001".to_owned()] } ), ( "1001".to_owned(), User { id: "1001".to_owned(), name: "Max".to_owned(), friend_ids: vec!["1000".to_owned()] } ), ].into_iter().collect() } } impl Context for Database {} fn main() { // GraphQLHandler takes a context factory function, the root object, // and the mutation object. If we don't have any mutations to expose, we // can use the empty tuple () to indicate absence. let graphql_endpoint = GraphQLHandler::new( context_factory, QueryRoot, EmptyMutation::<Database>::new()); // Start serving the schema at the root on port 8080. Iron::new(graphql_endpoint).http("localhost:8080").unwrap(); }
See the iron_handlers
module and the GraphQLHandler
documentation
for more information on what request methods are supported. There's also a
built-in GraphiQL handler included.
Modules
graphiql |
Utility module to generate a GraphiQL interface |
http |
Utilities for building HTTP endpoints in a library-agnostic manner |
iron_handlers |
Optional handlers for the Iron framework. Requires the |
meta |
Types used to describe a GraphQL schema |
parser |
Query parser and language utilities |
Macros
graphql_enum |
Expose simple enums |
graphql_input_object |
Create an input object |
graphql_interface |
Expose GraphQL interfaces |
graphql_object |
Expose GraphQL objects |
graphql_scalar |
Expose GraphQL scalars |
graphql_union |
Expose GraphQL unions |
jtry |
Helper macro to produce |
Structs
Arguments |
Field argument container |
EmptyMutation |
Utility type to define read-only schemas |
ExecutionError |
Error type for errors that occur during query execution |
Executor |
Query execution engine |
ID |
An ID as defined by the GraphQL specification |
Registry |
A type registry used to build schemas |
RootNode |
Root query node of a schema |
RuleError |
Query validation error |
Enums
GraphQLError |
An error that prevented query execution |
InputValue |
A JSON-like value that can be passed into the query execution, either out-of-band, or in-band as default variable values. These are not constant and might contain variables. |
Selection |
Entry in a GraphQL selection set |
Type |
A type literal in the syntax tree |
TypeKind |
GraphQL type kind |
Value |
Serializable value returned from query and field execution. |
Traits
Context |
Marker trait for types that can act as context objects for GraphQL types. |
FromContext |
Conversion trait for context types |
FromInputValue |
Parse an unstructured input value into a Rust data type. |
GraphQLType |
Primary trait used to expose Rust types in a GraphQL schema |
ResultExt |
Helper trait to produce |
ToInputValue |
Losslessly clones a Rust data type into an InputValue. |
Functions
execute |
Execute a query in a provided schema |
Type Definitions
ExecutionResult |
The result of resolving an unspecified field |
FieldResult |
The result of resolving the value of a field of type |
Variables |
The map of variables used for substitution during query execution |