diff --git a/advanced/implicit_and_explicit_null.html b/advanced/implicit_and_explicit_null.html index afe7c5b66..57b18d8d5 100644 --- a/advanced/implicit_and_explicit_null.html +++ b/advanced/implicit_and_explicit_null.html @@ -218,7 +218,7 @@
The last two cases rely on being able to distinguish between explicit and implicit null
.
Unfortunately, plain Option
is not capable to distinguish them. That's why in Juniper, this can be done using the Nullable
type:
Unfortunately, plain Option
is not capable to distinguish them. That's why in Juniper, this can be done using the Nullable
type:
extern crate juniper; use juniper::{graphql_object, FieldResult, GraphQLInputObject, Nullable}; diff --git a/advanced/lookahead.html b/advanced/lookahead.html index f783f1544..37749fb51 100644 --- a/advanced/lookahead.html +++ b/advanced/lookahead.html @@ -178,7 +178,7 @@
Look-ahead
In backtracking algorithms, look ahead is the generic term for a subprocedure that attempts to foresee the effects of choosing a branching variable to evaluate one of its values. The two main aims of look-ahead are to choose a variable to evaluate next and to choose the order of values to assign to it.
In GraphQL, look-ahead machinery allows us to introspect the currently executed GraphQL operation to see which fields has been actually selected by it.
-In Juniper, it's represented by the
+Executor::look_ahead()
method.In Juniper, it's represented by the
Executor::look_ahead()
method.#![allow(unused)] fn main() { extern crate juniper; @@ -210,7 +210,7 @@
Look-ahead
} }--TIP:
+S: ScalarValue
type parameter on the method is required here to keep theExecutor
being generic overScalarValue
types. We, instead, could have used theDefaultScalarValue
, which is the defaultScalarValue
type for theExecutor
, and make our code more ergonomic, but less flexible and generic.TIP:
S: ScalarValue
type parameter on the method is required here to keep theExecutor
being generic overScalarValue
types. We, instead, could have used theDefaultScalarValue
, which is the defaultScalarValue
type for theExecutor
, and make our code more ergonomic, but less flexible and generic.#![allow(unused)] fn main() { extern crate juniper; @@ -374,7 +374,7 @@
N+1 problem
SELECT id, name FROM cults WHERE id IN (1, 2, 3, 4);More features
-See more available look-ahead features in the API docs of the
+LookAheadSelection
and theLookAheadChildren
.See more available look-ahead features in the API docs of the
diff --git a/index.html b/index.html index fa5e45405..28f54e296 100644 --- a/index.html +++ b/index.html @@ -177,7 +177,7 @@LookAheadSelection
and theLookAheadChildren
.Introduction
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
Juniper is a library for creating GraphQL servers in Rust. Build type-safe and fast API servers with minimal boilerplate and configuration (we do try to make declaring and resolving GraphQL schemas as convenient as possible as Rust will allow).
+Juniper is a library for creating GraphQL servers in Rust. Build type-safe and fast API servers with minimal boilerplate and configuration (we do try to make declaring and resolving GraphQL schemas as convenient as Rust will allow).
Juniper doesn't include a web server itself, instead, it provides building blocks to make integration with existing web servers straightforward. It optionally provides a pre-built integration for some widely used web server frameworks in Rust ecosystem.
- Cargo crate
diff --git a/introduction.html b/introduction.html index fa5e45405..28f54e296 100644 --- a/introduction.html +++ b/introduction.html @@ -177,7 +177,7 @@Introduction
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
-Juniper is a library for creating GraphQL servers in Rust. Build type-safe and fast API servers with minimal boilerplate and configuration (we do try to make declaring and resolving GraphQL schemas as convenient as possible as Rust will allow).
+Juniper is a library for creating GraphQL servers in Rust. Build type-safe and fast API servers with minimal boilerplate and configuration (we do try to make declaring and resolving GraphQL schemas as convenient as Rust will allow).
Juniper doesn't include a web server itself, instead, it provides building blocks to make integration with existing web servers straightforward. It optionally provides a pre-built integration for some widely used web server frameworks in Rust ecosystem.
- Cargo crate
diff --git a/print.html b/print.html index 50044be3d..021449279 100644 --- a/print.html +++ b/print.html @@ -178,7 +178,7 @@Introduction
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
-Juniper is a library for creating GraphQL servers in Rust. Build type-safe and fast API servers with minimal boilerplate and configuration (we do try to make declaring and resolving GraphQL schemas as convenient as possible as Rust will allow).
+Juniper is a library for creating GraphQL servers in Rust. Build type-safe and fast API servers with minimal boilerplate and configuration (we do try to make declaring and resolving GraphQL schemas as convenient as Rust will allow).
Juniper doesn't include a web server itself, instead, it provides building blocks to make integration with existing web servers straightforward. It optionally provides a pre-built integration for some widely used web server frameworks in Rust ecosystem.
- Cargo crate
@@ -219,11 +219,11 @@API stability
Installation
[dependencies] -juniper = "0.16.0" +juniper = "0.16.1"
Schema
Exposing simple enums and structs as GraphQL types is just a matter of adding a custom derive attribute to them. Juniper includes support for basic Rust types that naturally map to GraphQL features, such as
-Option<T>
,Vec<T>
,Box<T>
,Arc<T>
,String
,f64
,i32
, references, slices and arrays.For more advanced mappings, Juniper provides multiple macros to map your Rust types to a GraphQL schema. The most important one is the
+#[graphql_object]
attribute that is used for declaring a GraphQL object with resolvers (typically used for declaringQuery
andMutation
roots).For more advanced mappings, Juniper provides multiple macros to map your Rust types to a GraphQL schema. The most important one is the
#[graphql_object]
attribute that is used for declaring a GraphQL object with resolvers (typically used for declaringQuery
andMutation
roots).# ![allow(unused_variables)] extern crate juniper; @@ -430,8 +430,8 @@
Execution
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:
-
- The easiest way, suitable for trivial cases, is to use the
-#[derive(GraphQLObject)]
attribute on a struct, as described below.- The other way, using the
+#[graphql_object]
attribute, is described in the "Complex fields" chapter.- The easiest way, suitable for trivial cases, is to use the
+#[derive(GraphQLObject)]
attribute on a struct, as described below.- 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:
@@ -447,7 +447,7 @@Trivial
fn main() {}This creates a GraphQL object type called
Person
, with two fields:name
of typeString!
, andage
of typeInt!
. Because of Rust's type system, everything is exported as non-null
by default.-TIP: If a
+null
able field is required, the most obvious way is to useOption
. OrNullable
for distinguishing between explicit and implicitnull
s.TIP: If a
null
able field is required, the most obvious way is to useOption
. OrNullable
for distinguishing between explicit and implicitnull
s.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:
@@ -564,7 +564,7 @@Ignoring
fn main() {}
-TIP: See more available features in the API docs of the
+#[derive(GraphQLObject)]
attribute.TIP: See more available features in the API docs of the
#[derive(GraphQLObject)]
attribute.
GraphQL object fields can be of any GraphQL type, except input objects.
@@ -594,7 +594,7 @@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:
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}; @@ -772,7 +772,7 @@
Ignoring
fn main() {}
-TIP: See more available features in the API docs of the
+#[graphql_object]
attribute.TIP: See more available features in the API docs of the
#[graphql_object]
attribute.
Context is a feature in Juniper that lets field resolvers access global data, most commonly database connections or authentication information.
@@ -950,12 +950,12 @@FieldResult<T>
is an alias for Result<T, FieldError>
, which is the error type all fallible fields must return. By using the ?
operator, any type that implements the Display
trait (which most of the error types out there do) can be automatically converted into a FieldError
.
FieldResult<T>
is an alias for Result<T, FieldError>
, which is the error type all fallible fields must return. By using the ?
operator, any type that implements the Display
trait (which most of the error types out there do) can be automatically converted into a FieldError
.
-TIP: If a custom conversion into a
+FieldError
is needed (to fill upextensions
, for example), theIntoFieldError
trait should be implemented.TIP: If a custom conversion into a
FieldError
is needed (to fill upextensions
, for example), theIntoFieldError
trait should be implemented.
-NOTE:
+FieldError
s are GraphQL field errors and are not visible in a GraphQL schema in any way.NOTE:
FieldError
s are GraphQL field errors and are not visible in a GraphQL schema in any way.
null
, and partial errorsJuniper's error behavior conforms to the GraphQL specification.
@@ -1002,7 +1002,7 @@Sometimes it's desirable to return additional structured error information to clients. This can be accomplished by implementing the IntoFieldError
trait:
Sometimes it's desirable to return additional structured error information to clients. This can be accomplished by implementing the IntoFieldError
trait:
#[macro_use] extern crate juniper; use juniper::{graphql_object, FieldError, IntoFieldError, ScalarValue}; @@ -1408,7 +1408,7 @@
struct, or a trait (in case fields have arguments), which acts only as a blueprint describing the required list of fields, and is not used in runtime at all.
An auto-generated enum, representing a dispatchable value-type for the GraphQL interfaces, which may be referred and returned by other fields. -This may be done by using either the
+#[graphql_interface]
attribute or the#[derive(GraphQLInterface)]
:This may be done by using either the
#[graphql_interface]
attribute or the#[derive(GraphQLInterface)]
:extern crate juniper; use juniper::{graphql_interface, GraphQLInterface, GraphQLObject}; @@ -1750,14 +1750,14 @@
Ignoring
fn main() {}-TIP: See more available features in the API docs of the
+#[graphql_interface]
attribute.TIP: See more available features in the API docs of the
#[graphql_interface]
attribute.Unions
GraphQL unions represent an object that could be one of a list of GraphQL object types, but provides for no guaranteed fields between those types. They also differ from interfaces in that object types declare what interfaces they implement, but are not aware of what unions contain them.
From the server's point of view, GraphQL unions are somewhat similar to interfaces: the main difference is that they don't contain fields on their own, and so, we only need to represent a value, dispatchable into concrete objects.
-Obviously, the most straightforward approach to express GraphQL unions in Rust is to use enums. In Juniper this may be done by using
+#[derive(GraphQLInterface)]
attribute on them:Obviously, the most straightforward approach to express GraphQL unions in Rust is to use enums. In Juniper this may be done by using
#[derive(GraphQLInterface)]
attribute on them:extern crate derive_more; extern crate juniper; use derive_more::From; @@ -1887,14 +1887,14 @@
Ignoring
WARNING: It's the library user's responsibility to ensure that ignored enum variant is never returned from resolvers, otherwise resolving the GraphQL query will panic in runtime.
-TIP: See more available features in the API docs of the
+#[derive(GraphQLUnion)]
attribute.TIP: See more available features in the API docs of the
#[derive(GraphQLUnion)]
attribute.Enums
-GraphQL enum types, like scalar types, also represent leaf values in a GraphQL type system. However enum types describe the set of possible values.
Enums are not references for a numeric value, but are unique values in their own right. They may serialize as a string: the name of the represented value.
With Juniper a GraphQL enum may be defined by using the
+#[derive(GraphQLEnum)]
attribute on a Rust enum as long as its variants do not have any fields:With Juniper a GraphQL enum may be defined by using the
#[derive(GraphQLEnum)]
attribute on a Rust enum as long as its variants do not have any fields:extern crate juniper; use juniper::GraphQLEnum; @@ -2001,14 +2001,14 @@
Ignoring
fn main() {}-TIP: See more available features in the API docs of the
+#[derive(GraphQLEnum)]
attribute.TIP: See more available features in the API docs of the
#[derive(GraphQLEnum)]
attribute.Input objects
-Fields may accept arguments to configure their behavior. These inputs are often scalars or enums, but they sometimes need to represent more complex values.
A GraphQL input object defines a set of input fields; the input fields are either scalars, enums, or other input objects. This allows arguments to accept arbitrarily complex structs.
In Juniper, defining a GraphQL input object is quite straightforward and similar to how trivial GraphQL objects are defined - by using the
+#[derive(GraphQLInputObject)]
attribute on a Rust struct:In Juniper, defining a GraphQL input object is quite straightforward and similar to how trivial GraphQL objects are defined - by using the
#[derive(GraphQLInputObject)]
attribute on a Rust struct:#![allow(unused_variables)] extern crate juniper; use juniper::{graphql_object, GraphQLInputObject, GraphQLObject}; @@ -2128,7 +2128,7 @@
Ignoring
fn main() {}-TIP: See more available features in the API docs of the
+#[derive(GraphQLInputObject)]
attribute.TIP: See more available features in the API docs of the
#[derive(GraphQLInputObject)]
attribute.Scalars
GraphQL scalars represent primitive leaf values in a GraphQL type system: numbers, strings, and booleans.
@@ -2150,7 +2150,7 @@Built-in
Custom
We can create custom scalars for other primitive values, but they are still limited in the data types for representation, and only introduce additional semantic meaning. This, also, often requires coordination with the client library, intended to consume the API we're building.
-Custom scalars can be defined in Juniper by using either
+#[derive(GraphQLScalar)]
or#[graphql_scalar]
attributes, which do work pretty much the same way (except,#[derive(GraphQLScalar)]
cannot be used on type aliases).Custom scalars can be defined in Juniper by using either
#[derive(GraphQLScalar)]
or#[graphql_scalar]
attributes, which do work pretty much the same way (except,#[derive(GraphQLScalar)]
cannot be used on type aliases).Transparent delegation
Quite often, we want to create a custom GraphQL scalar type by just wrapping an existing one, inheriting all its behavior. In Rust, this is often called as "newtype pattern". This may be achieved by providing a
#[graphql(transparent)]
attribute to the definition:extern crate juniper; @@ -2410,12 +2410,12 @@
Full behavior fn main() {}
-TIP: See more available features in the API docs of the
+#[derive(GraphQLScalar)]
and#[graphql_scalar]
attributes.TIP: See more available features in the API docs of the
#[derive(GraphQLScalar)]
and#[graphql_scalar]
attributes.Foreign
-For implementing custom scalars on foreign types there is
+#[graphql_scalar]
attribute.For implementing custom scalars on foreign types there is
#[graphql_scalar]
attribute.-NOTE: To satisfy orphan rules, we should provide a local
+ScalarValue
implementation.NOTE: To satisfy orphan rules, we should provide a local
ScalarValue
implementation.extern crate juniper; mod date { @@ -2494,10 +2494,10 @@
Object type.
The query, mutation, and subscription root types must all be different types if provided.
-In Juniper, the
+RootNode
type represents a schema. When the schema is first created, Juniper will traverse the entire object graph and register all types it can find. This means that if we define a GraphQL object somewhere but never use or reference it, it won't be exposed in a GraphQL schema.In Juniper, the
RootNode
type represents a schema. When the schema is first created, Juniper will traverse the entire object graph and register all types it can find. This means that if we define a GraphQL object somewhere but never use or reference it, it won't be exposed in a GraphQL schema.Both query and mutation objects are regular GraphQL objects, defined like any other object in Juniper. The mutation and subscription objects, however, are optional, since schemas can be read-only and do not require subscriptions.
-TIP: If mutation/subscription functionality is not needed, consider using the predefined
+EmptyMutation
/EmptySubscription
types for stubbing them in aRootNode
.TIP: If mutation/subscription functionality is not needed, consider using the predefined
EmptyMutation
/EmptySubscription
types for stubbing them in aRootNode
.extern crate juniper; use juniper::{ @@ -2539,7 +2539,7 @@
Export
Many tools in GraphQL ecosystem require a schema definition to operate on. With Juniper we can export our GraphQL schema defined in Rust code either represented in the GraphQL schema language or in JSON.
SDL (schema definition language)
-To generate an SDL (schema definition language) representation of a GraphQL schema defined in Rust code, the
+as_sdl()
method should be used for the direct extraction (requires enabling theschema-language
Juniper feature):To generate an SDL (schema definition language) representation of a GraphQL schema defined in Rust code, the
as_sdl()
method should be used for the direct extraction (requires enabling theschema-language
Juniper feature):extern crate juniper; use juniper::{ graphql_object, EmptyMutation, EmptySubscription, FieldResult, RootNode, @@ -2578,7 +2578,7 @@
JSON
-To export a GraphQL schema defined in Rust code as JSON (often referred to as
+schema.json
), the specially crafted introspection query should be issued. Juniper provides a convenienceintrospect()
function to introspect the entire schema, which result can be serialized into JSON:To export a GraphQL schema defined in Rust code as JSON (often referred to as
schema.json
), the specially crafted introspection query should be issued. Juniper provides a convenienceintrospect()
function to introspect the entire schema, which result can be serialized into JSON:extern crate juniper; extern crate serde_json; use juniper::{ @@ -2662,9 +2662,9 @@
JSON
fn main () {}Coordinator
-GraphQL subscriptions require a bit more resources than regular queries and provide a great vector for DoS attacks. This can can bring down a server easily if not handled correctly. The
-SubscriptionCoordinator
trait provides coordination logic to enable functionality like DoS attacks mitigation and resource limits.The
-SubscriptionCoordinator
contains the schema and can keep track of opened connections, handle subscription start and end, and maintain a global ID for each subscription. Each time a connection is established, theSubscriptionCoordinator
spawns a [32], which handles a single connection, providing resolver logic for a client stream as well as reconnection and shutdown logic.While we can implement
+SubscriptionCoordinator
ourselves, Juniper contains a simple and generic implementation calledCoordinator
. Thesubscribe
method returns aFuture
resolving into aResult<Connection, GraphQLError>
, whereConnection
is aStream
of values returned by the operation, and aGraphQLError
is the error when the subscription operation fails.GraphQL subscriptions require a bit more resources than regular queries and provide a great vector for DoS attacks. This can can bring down a server easily if not handled correctly. The
+SubscriptionCoordinator
trait provides coordination logic to enable functionality like DoS attacks mitigation and resource limits.The
+SubscriptionCoordinator
contains the schema and can keep track of opened connections, handle subscription start and end, and maintain a global ID for each subscription. Each time a connection is established, theSubscriptionCoordinator
spawns a [32], which handles a single connection, providing resolver logic for a client stream as well as reconnection and shutdown logic.While we can implement
SubscriptionCoordinator
ourselves, Juniper contains a simple and generic implementation calledCoordinator
. Thesubscribe
method returns aFuture
resolving into aResult<Connection, GraphQLError>
, whereConnection
is aStream
of values returned by the operation, and aGraphQLError
is the error when the subscription operation fails.extern crate futures; extern crate juniper; extern crate juniper_subscriptions; @@ -2764,7 +2764,7 @@
Disabling
-Disabling introspection in production is a widely debated topic, but we believe it’s one of the first things you can do to harden your GraphQL API in production.
Some security requirements and considerations may mandate to disable GraphQL schema introspection in production environments. In Juniper this can be achieved by using the
+RootNode::disable_introspection()
method:Some security requirements and considerations may mandate to disable GraphQL schema introspection in production environments. In Juniper this can be achieved by using the
RootNode::disable_introspection()
method:extern crate juniper; use juniper::{ graphql_object, graphql_vars, EmptyMutation, EmptySubscription, GraphQLError, @@ -2944,7 +2944,7 @@
WebSocket
mutation { patchUser(patch: {}) }
The last two cases rely on being able to distinguish between explicit and implicit
-null
.Unfortunately, plain
+Option
is not capable to distinguish them. That's why in Juniper, this can be done using theNullable
type:Unfortunately, plain
Option
is not capable to distinguish them. That's why in Juniper, this can be done using theNullable
type:extern crate juniper; use juniper::{graphql_object, FieldResult, GraphQLInputObject, Nullable}; @@ -3257,7 +3257,7 @@
Full exampleIn backtracking algorithms, look ahead is the generic term for a subprocedure that attempts to foresee the effects of choosing a branching variable to evaluate one of its values. The two main aims of look-ahead are to choose a variable to evaluate next and to choose the order of values to assign to it.
In GraphQL, look-ahead machinery allows us to introspect the currently executed GraphQL operation to see which fields has been actually selected by it.
-In Juniper, it's represented by the
+Executor::look_ahead()
method.In Juniper, it's represented by the
Executor::look_ahead()
method.#![allow(unused)] fn main() { extern crate juniper; @@ -3289,7 +3289,7 @@
Full example}
-TIP:
+S: ScalarValue
type parameter on the method is required here to keep theExecutor
being generic overScalarValue
types. We, instead, could have used theDefaultScalarValue
, which is the defaultScalarValue
type for theExecutor
, and make our code more ergonomic, but less flexible and generic.TIP:
S: ScalarValue
type parameter on the method is required here to keep theExecutor
being generic overScalarValue
types. We, instead, could have used theDefaultScalarValue
, which is the defaultScalarValue
type for theExecutor
, and make our code more ergonomic, but less flexible and generic.#![allow(unused)] fn main() { extern crate juniper; @@ -3453,7 +3453,7 @@
N+1 problem
More features
-See more available look-ahead features in the API docs of the
+LookAheadSelection
and theLookAheadChildren
.See more available look-ahead features in the API docs of the
LookAheadSelection
and theLookAheadChildren
.Eager loading
As a further evolution of the dealing with the N+1 problem via look-ahead, we may systematically remodel Rust types mapping to GraphQL ones in the way to encourage doing eager preloading of data for its fields and using the already preloaded data when resolving a particular field.
At the moment, this approach is represented with the
diff --git a/quickstart.html b/quickstart.html index 8cd10f7da..aaeb6af8e 100644 --- a/quickstart.html +++ b/quickstart.html @@ -181,11 +181,11 @@juniper-eager-loading
crate for Juniper.Quickstart
Installation
[dependencies] -juniper = "0.16.0" +juniper = "0.16.1"
Schema
Exposing simple enums and structs as GraphQL types is just a matter of adding a custom derive attribute to them. Juniper includes support for basic Rust types that naturally map to GraphQL features, such as
-Option<T>
,Vec<T>
,Box<T>
,Arc<T>
,String
,f64
,i32
, references, slices and arrays.For more advanced mappings, Juniper provides multiple macros to map your Rust types to a GraphQL schema. The most important one is the
+#[graphql_object]
attribute that is used for declaring a GraphQL object with resolvers (typically used for declaringQuery
andMutation
roots).For more advanced mappings, Juniper provides multiple macros to map your Rust types to a GraphQL schema. The most important one is the
#[graphql_object]
attribute that is used for declaring a GraphQL object with resolvers (typically used for declaringQuery
andMutation
roots).# ![allow(unused_variables)] extern crate juniper; diff --git a/schema/index.html b/schema/index.html index 152e355d8..50219167b 100644 --- a/schema/index.html +++ b/schema/index.html @@ -185,10 +185,10 @@
Schema
Similarly, the subscription root operation type is also optional; if it is not provided, the service does not support subscriptions. If it is provided, it must be an Object type.
The query, mutation, and subscription root types must all be different types if provided.
-In Juniper, the
+RootNode
type represents a schema. When the schema is first created, Juniper will traverse the entire object graph and register all types it can find. This means that if we define a GraphQL object somewhere but never use or reference it, it won't be exposed in a GraphQL schema.In Juniper, the
RootNode
type represents a schema. When the schema is first created, Juniper will traverse the entire object graph and register all types it can find. This means that if we define a GraphQL object somewhere but never use or reference it, it won't be exposed in a GraphQL schema.Both query and mutation objects are regular GraphQL objects, defined like any other object in Juniper. The mutation and subscription objects, however, are optional, since schemas can be read-only and do not require subscriptions.
-TIP: If mutation/subscription functionality is not needed, consider using the predefined
+EmptyMutation
/EmptySubscription
types for stubbing them in aRootNode
.TIP: If mutation/subscription functionality is not needed, consider using the predefined
EmptyMutation
/EmptySubscription
types for stubbing them in aRootNode
.extern crate juniper; use juniper::{ @@ -230,7 +230,7 @@
Schema
Export
Many tools in GraphQL ecosystem require a schema definition to operate on. With Juniper we can export our GraphQL schema defined in Rust code either represented in the GraphQL schema language or in JSON.
SDL (schema definition language)
-To generate an SDL (schema definition language) representation of a GraphQL schema defined in Rust code, the
+as_sdl()
method should be used for the direct extraction (requires enabling theschema-language
Juniper feature):To generate an SDL (schema definition language) representation of a GraphQL schema defined in Rust code, the
as_sdl()
method should be used for the direct extraction (requires enabling theschema-language
Juniper feature):extern crate juniper; use juniper::{ graphql_object, EmptyMutation, EmptySubscription, FieldResult, RootNode, @@ -269,7 +269,7 @@
JSON
-To export a GraphQL schema defined in Rust code as JSON (often referred to as
+schema.json
), the specially crafted introspection query should be issued. Juniper provides a convenienceintrospect()
function to introspect the entire schema, which result can be serialized into JSON:To export a GraphQL schema defined in Rust code as JSON (often referred to as
schema.json
), the specially crafted introspection query should be issued. Juniper provides a convenienceintrospect()
function to introspect the entire schema, which result can be serialized into JSON:extern crate juniper; extern crate serde_json; use juniper::{ diff --git a/schema/introspection.html b/schema/introspection.html index 84397d6e8..88d291a14 100644 --- a/schema/introspection.html +++ b/schema/introspection.html @@ -195,7 +195,7 @@
Disabling
-Disabling introspection in production is a widely debated topic, but we believe it’s one of the first things you can do to harden your GraphQL API in production.
Some security requirements and considerations may mandate to disable GraphQL schema introspection in production environments. In Juniper this can be achieved by using the
+RootNode::disable_introspection()
method:Some security requirements and considerations may mandate to disable GraphQL schema introspection in production environments. In Juniper this can be achieved by using the
RootNode::disable_introspection()
method:extern crate juniper; use juniper::{ graphql_object, graphql_vars, EmptyMutation, EmptySubscription, GraphQLError, diff --git a/schema/subscriptions.html b/schema/subscriptions.html index 413eb4629..82279e789 100644 --- a/schema/subscriptions.html +++ b/schema/subscriptions.html @@ -218,9 +218,9 @@
Subscriptions fn main () {}
Coordinator
-GraphQL subscriptions require a bit more resources than regular queries and provide a great vector for DoS attacks. This can can bring down a server easily if not handled correctly. The
-SubscriptionCoordinator
trait provides coordination logic to enable functionality like DoS attacks mitigation and resource limits.The
-SubscriptionCoordinator
contains the schema and can keep track of opened connections, handle subscription start and end, and maintain a global ID for each subscription. Each time a connection is established, theSubscriptionCoordinator
spawns a [32], which handles a single connection, providing resolver logic for a client stream as well as reconnection and shutdown logic.While we can implement
+SubscriptionCoordinator
ourselves, Juniper contains a simple and generic implementation calledCoordinator
. Thesubscribe
method returns aFuture
resolving into aResult<Connection, GraphQLError>
, whereConnection
is aStream
of values returned by the operation, and aGraphQLError
is the error when the subscription operation fails.GraphQL subscriptions require a bit more resources than regular queries and provide a great vector for DoS attacks. This can can bring down a server easily if not handled correctly. The
+SubscriptionCoordinator
trait provides coordination logic to enable functionality like DoS attacks mitigation and resource limits.The
+SubscriptionCoordinator
contains the schema and can keep track of opened connections, handle subscription start and end, and maintain a global ID for each subscription. Each time a connection is established, theSubscriptionCoordinator
spawns a [32], which handles a single connection, providing resolver logic for a client stream as well as reconnection and shutdown logic.While we can implement
SubscriptionCoordinator
ourselves, Juniper contains a simple and generic implementation calledCoordinator
. Thesubscribe
method returns aFuture
resolving into aResult<Connection, GraphQLError>
, whereConnection
is aStream
of values returned by the operation, and aGraphQLError
is the error when the subscription operation fails.extern crate futures; extern crate juniper; extern crate juniper_subscriptions; diff --git a/searchindex.js b/searchindex.js index f86992934..ff04a2216 100644 --- a/searchindex.js +++ b/searchindex.js @@ -1 +1 @@ -Object.assign(window.search, {"doc_urls":["introduction.html#introduction","introduction.html#features","introduction.html#integrations","introduction.html#types","introduction.html#web-server-frameworks","introduction.html#api-stability","quickstart.html#quickstart","quickstart.html#installation","quickstart.html#schema","quickstart.html#execution","types/index.html#type-system","types/objects/index.html#objects","types/objects/index.html#trivial","types/objects/index.html#documentation","types/objects/index.html#renaming","types/objects/index.html#deprecation","types/objects/index.html#ignoring","types/objects/index.html#relationships","types/objects/complex_fields.html#complex-fields","types/objects/complex_fields.html#default-arguments","types/objects/complex_fields.html#renaming","types/objects/complex_fields.html#documentation-and-deprecation","types/objects/complex_fields.html#ignoring","types/objects/context.html#context","types/objects/context.html#mutating-and-mutable-references","types/objects/error/index.html#error-handling","types/objects/error/index.html#comparison","types/objects/error/field.html#field-errors","types/objects/error/field.html#error-payloads-null-and-partial-errors","types/objects/error/field.html#additional-information","types/objects/error/schema.html#schema-errors","types/objects/error/schema.html#example-simple","types/objects/error/schema.html#example-complex","types/objects/error/schema.html#example-complex-with-critical-errors","types/objects/error/schema.html#example-shopify-api","types/objects/error/schema.html#example-non-struct--objects","types/objects/generics.html#generics","types/interfaces.html#interfaces","types/interfaces.html#interfaces-implementing-other-interfaces","types/interfaces.html#subtyping-and-additional-nullable-arguments","types/interfaces.html#default-arguments","types/interfaces.html#renaming","types/interfaces.html#documentation-and-deprecation","types/interfaces.html#ignoring","types/unions.html#unions","types/unions.html#renaming","types/unions.html#documentation","types/unions.html#ignoring","types/enums.html#enums","types/enums.html#renaming","types/enums.html#documentation-and-deprecation","types/enums.html#ignoring","types/input_objects.html#input-objects","types/input_objects.html#renaming","types/input_objects.html#documentation","types/input_objects.html#ignoring","types/scalars.html#scalars","types/scalars.html#built-in","types/scalars.html#custom","types/scalars.html#transparent-delegation","types/scalars.html#resolving","types/scalars.html#input-value-parsing","types/scalars.html#token-parsing","types/scalars.html#full-behavior","types/scalars.html#foreign","types/scalars.html#supported-out-of-the-box","schema/index.html#schema","schema/index.html#export","schema/index.html#sdl-schema-definition-language","schema/index.html#json","schema/subscriptions.html#subscriptions","schema/subscriptions.html#coordinator","schema/subscriptions.html#websocket","schema/introspection.html#introspection","schema/introspection.html#disabling","serve/index.html#serving","serve/index.html#web-server-frameworks","serve/index.html#officially-supported","serve/index.html#websocket","serve/batching.html#batching","advanced/index.html#advanced-topics","advanced/implicit_and_explicit_null.html#implicit-and-explicit-null","advanced/n_plus_1.html#n1-problem","advanced/dataloader.html#dataloader","advanced/dataloader.html#caching","advanced/dataloader.html#full-example","advanced/lookahead.html#look-ahead","advanced/lookahead.html#n1-problem","advanced/lookahead.html#more-features","advanced/eager_loading.html#eager-loading","advanced/eager_loading.html#how-this-library-works-at-a-high-level","advanced/eager_loading.html#a-real-example","advanced/eager_loading.html#full-example"],"index":{"documentStore":{"docInfo":{"0":{"body":92,"breadcrumbs":2,"title":1},"1":{"body":33,"breadcrumbs":2,"title":1},"10":{"body":43,"breadcrumbs":4,"title":2},"11":{"body":51,"breadcrumbs":4,"title":1},"12":{"body":59,"breadcrumbs":4,"title":1},"13":{"body":125,"breadcrumbs":4,"title":1},"14":{"body":109,"breadcrumbs":4,"title":1},"15":{"body":49,"breadcrumbs":4,"title":1},"16":{"body":53,"breadcrumbs":4,"title":1},"17":{"body":55,"breadcrumbs":4,"title":1},"18":{"body":127,"breadcrumbs":7,"title":2},"19":{"body":67,"breadcrumbs":7,"title":2},"2":{"body":0,"breadcrumbs":2,"title":1},"20":{"body":101,"breadcrumbs":6,"title":1},"21":{"body":108,"breadcrumbs":7,"title":2},"22":{"body":75,"breadcrumbs":6,"title":1},"23":{"body":179,"breadcrumbs":5,"title":1},"24":{"body":146,"breadcrumbs":7,"title":3},"25":{"body":37,"breadcrumbs":7,"title":2},"26":{"body":76,"breadcrumbs":6,"title":1},"27":{"body":119,"breadcrumbs":9,"title":2},"28":{"body":113,"breadcrumbs":12,"title":5},"29":{"body":96,"breadcrumbs":9,"title":2},"3":{"body":33,"breadcrumbs":2,"title":1},"30":{"body":82,"breadcrumbs":9,"title":2},"31":{"body":177,"breadcrumbs":9,"title":2},"32":{"body":145,"breadcrumbs":9,"title":2},"33":{"body":130,"breadcrumbs":11,"title":4},"34":{"body":13,"breadcrumbs":10,"title":3},"35":{"body":90,"breadcrumbs":11,"title":4},"36":{"body":168,"breadcrumbs":5,"title":1},"37":{"body":263,"breadcrumbs":4,"title":1},"38":{"body":120,"breadcrumbs":6,"title":3},"39":{"body":265,"breadcrumbs":7,"title":4},"4":{"body":16,"breadcrumbs":4,"title":3},"40":{"body":49,"breadcrumbs":5,"title":2},"41":{"body":113,"breadcrumbs":4,"title":1},"42":{"body":104,"breadcrumbs":5,"title":2},"43":{"body":68,"breadcrumbs":4,"title":1},"44":{"body":93,"breadcrumbs":4,"title":1},"45":{"body":61,"breadcrumbs":4,"title":1},"46":{"body":107,"breadcrumbs":4,"title":1},"47":{"body":107,"breadcrumbs":4,"title":1},"48":{"body":54,"breadcrumbs":4,"title":1},"49":{"body":113,"breadcrumbs":4,"title":1},"5":{"body":7,"breadcrumbs":3,"title":2},"50":{"body":99,"breadcrumbs":5,"title":2},"51":{"body":51,"breadcrumbs":4,"title":1},"52":{"body":87,"breadcrumbs":6,"title":2},"53":{"body":112,"breadcrumbs":5,"title":1},"54":{"body":70,"breadcrumbs":5,"title":1},"55":{"body":85,"breadcrumbs":5,"title":1},"56":{"body":12,"breadcrumbs":4,"title":1},"57":{"body":55,"breadcrumbs":4,"title":1},"58":{"body":41,"breadcrumbs":4,"title":1},"59":{"body":129,"breadcrumbs":5,"title":2},"6":{"body":29,"breadcrumbs":2,"title":1},"60":{"body":46,"breadcrumbs":4,"title":1},"61":{"body":61,"breadcrumbs":6,"title":3},"62":{"body":102,"breadcrumbs":5,"title":2},"63":{"body":234,"breadcrumbs":5,"title":2},"64":{"body":97,"breadcrumbs":4,"title":1},"65":{"body":77,"breadcrumbs":6,"title":3},"66":{"body":213,"breadcrumbs":2,"title":1},"67":{"body":20,"breadcrumbs":2,"title":1},"68":{"body":72,"breadcrumbs":5,"title":4},"69":{"body":98,"breadcrumbs":2,"title":1},"7":{"body":3,"breadcrumbs":2,"title":1},"70":{"body":149,"breadcrumbs":3,"title":1},"71":{"body":213,"breadcrumbs":3,"title":1},"72":{"body":9,"breadcrumbs":3,"title":1},"73":{"body":60,"breadcrumbs":3,"title":1},"74":{"body":97,"breadcrumbs":3,"title":1},"75":{"body":18,"breadcrumbs":2,"title":1},"76":{"body":10,"breadcrumbs":4,"title":3},"77":{"body":72,"breadcrumbs":3,"title":2},"78":{"body":95,"breadcrumbs":2,"title":1},"79":{"body":141,"breadcrumbs":3,"title":1},"8":{"body":339,"breadcrumbs":2,"title":1},"80":{"body":16,"breadcrumbs":4,"title":2},"81":{"body":223,"breadcrumbs":8,"title":3},"82":{"body":228,"breadcrumbs":6,"title":2},"83":{"body":443,"breadcrumbs":6,"title":1},"84":{"body":68,"breadcrumbs":6,"title":1},"85":{"body":12,"breadcrumbs":7,"title":2},"86":{"body":167,"breadcrumbs":8,"title":2},"87":{"body":276,"breadcrumbs":8,"title":2},"88":{"body":10,"breadcrumbs":8,"title":2},"89":{"body":58,"breadcrumbs":10,"title":2},"9":{"body":106,"breadcrumbs":2,"title":1},"90":{"body":130,"breadcrumbs":12,"title":4},"91":{"body":326,"breadcrumbs":10,"title":2},"92":{"body":12,"breadcrumbs":10,"title":2}},"docs":{"0":{"body":"GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools. Juniper is a library for creating GraphQL servers in Rust . Build type-safe and fast API servers with minimal boilerplate and configuration (we do try to make declaring and resolving GraphQL schemas as convenient as possible as Rust will allow). Juniper doesn't include a web server itself, instead, it provides building blocks to make integration with existing web servers straightforward. It optionally provides a pre-built integration for some widely used web server frameworks in Rust ecosystem. Cargo crate API reference","breadcrumbs":"Introduction » Introduction","id":"0","title":"Introduction"},"1":{"body":"Juniper supports the full GraphQL query language according to the specification (October 2021) . NOTE : As an exception to other GraphQL libraries for other languages, Juniper builds non-null types by default. A field of type Vec
will be converted into [Episode!]!. The corresponding Rust type for a nullable [Episode] would be Option >> instead.","breadcrumbs":"Introduction » Features","id":"1","title":"Features"},"10":{"body":"Most of the work in working with Juniper consists of mapping the GraphQL type system to the Rust types our application uses. Juniper provides some convenient abstractions making this process as painless as possible. Find out more in the individual chapters below: Objects Complex fields Context Error handling Field errors Schema errors Generics Interfaces Unions Enums Input objects Scalars","breadcrumbs":"Type system » Type system","id":"10","title":"Type system"},"11":{"body":"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 : The easiest way, suitable for trivial cases, is to use the #[derive(GraphQLObject)] attribute on a struct , as described below. The other way, using the #[graphql_object] attribute , is described in the \"Complex fields\" chapter .","breadcrumbs":"Type system » Objects » Objects","id":"11","title":"Objects"},"12":{"body":"While any type in Rust can be exposed as a GraphQL object , the most common one is a struct : # extern crate juniper;\n# use juniper::GraphQLObject;\n#\n#[derive(GraphQLObject)]\nstruct Person { name: String, age: i32,\n}\n#\n# 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 .","breadcrumbs":"Type system » Objects » Trivial","id":"12","title":"Trivial"},"13":{"body":"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;\n# use juniper::GraphQLObject;\n#\n/// Information about a person.\n#[derive(GraphQLObject)]\nstruct Person { /// The person's full name, including both first and last names. name: String, /// The person's age in years, rounded down. age: i32,\n}\n#\n# 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;\n# use juniper::GraphQLObject;\n#\n/// This doc comment is visible only in Rust API docs.\n#[derive(GraphQLObject)]\n#[graphql(description = \"This description is visible only in GraphQL schema.\")]\nstruct 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,\n}\n#\n# fn main() {}","breadcrumbs":"Type system » Objects » Documentation","id":"13","title":"Documentation"},"14":{"body":"By default, struct fields are converted from Rust 's standard snake_case naming convention into GraphQL 's camelCase convention: # extern crate juniper;\n# use juniper::GraphQLObject;\n#\n#[derive(GraphQLObject)]\nstruct Person { first_name: String, // exposed as `firstName` in GraphQL schema last_name: String, // exposed as `lastName` in GraphQL schema\n}\n#\n# fn main() {} We can override the name by using the #[graphql(name = \"...\")] attribute: # extern crate juniper;\n# use juniper::GraphQLObject;\n#\n#[derive(GraphQLObject)]\n#[graphql(name = \"WebPerson\")] // now exposed as `WebPerson` in GraphQL schema\nstruct Person { name: String, age: i32, #[graphql(name = \"websiteURL\")] website_url: Option , // now exposed as `websiteURL` in GraphQL schema\n}\n#\n# fn main() {} Or provide a different renaming policy for all the struct fields: # extern crate juniper;\n# use juniper::GraphQLObject;\n#\n#[derive(GraphQLObject)]\n#[graphql(rename_all = \"none\")] // disables any renaming\nstruct Person { name: String, age: i32, website_url: Option , // exposed as `website_url` in GraphQL schema\n}\n#\n# fn main() {} TIP : Supported policies are: SCREAMING_SNAKE_CASE, camelCase and none (disables any renaming).","breadcrumbs":"Type system » Objects » Renaming","id":"14","title":"Renaming"},"15":{"body":"To deprecate a GraphQL object field, either the #[graphql(deprecated = \"...\")] attribute, or Rust's #[deprecated] attribute , should be used: # extern crate juniper;\n# use juniper::GraphQLObject;\n#\n#[derive(GraphQLObject)]\nstruct 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,\n}\n#\n# fn main() {} NOTE : Only GraphQL object / interface fields and GraphQL enum values can be deprecated .","breadcrumbs":"Type system » Objects » Deprecation","id":"15","title":"Deprecation"},"16":{"body":"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)]\n# extern crate juniper;\n# use juniper::GraphQLObject;\n#\n#[derive(GraphQLObject)]\nstruct 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\n}\n#\n# fn main() {} TIP : See more available features in the API docs of the #[derive(GraphQLObject)] attribute.","breadcrumbs":"Type system » Objects » Ignoring","id":"16","title":"Ignoring"},"17":{"body":"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;\n# use juniper::GraphQLObject;\n#\n#[derive(GraphQLObject)]\nstruct Person { name: String, age: i32,\n} #[derive(GraphQLObject)]\nstruct House { address: Option , // converted into `String` (`null`able) inhabitants: Vec , // converted into `[Person!]!`\n}\n#\n# fn main() {} Because Person is a valid GraphQL type, we can have a Vec in a struct , and it'll be automatically converted into a list of non-nullable Person objects .","breadcrumbs":"Type system » Objects » Relationships","id":"17","title":"Relationships"},"18":{"body":"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: Calling non-trivial logic while executing the field (like querying database, etc.). Accepting field arguments . Defining a circular GraphQL object , where one of its fields returns the type itself. Using some other (non- struct ) Rust type to represent a GraphQL object . 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;\n# use juniper::{graphql_object, GraphQLObject};\n#\n#[derive(GraphQLObject)]\nstruct Person { name: String, age: i32,\n} struct House { inhabitants: Vec ,\n} // Defines the `House` GraphQL object.\n#[graphql_object]\nimpl 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) }\n}\n#\n# 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 .","breadcrumbs":"Type system » Objects » Complex fields » Complex fields","id":"18","title":"Complex fields"},"19":{"body":"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;\n# use juniper::graphql_object;\n#\nstruct Person; #[graphql_object]\nimpl 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}\") }\n}\n#\n# fn main() {}","breadcrumbs":"Type system » Objects » Complex fields » Default arguments","id":"19","title":"Default arguments"},"2":{"body":"","breadcrumbs":"Introduction » Integrations","id":"2","title":"Integrations"},"20":{"body":"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;\n# use juniper::graphql_object;\n#\nstruct Person; #[graphql_object]\n#[graphql(name = \"PersonObject\")]\nimpl 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 }\n}\n#\n# fn main() {} Or provide a different renaming policy for all the defined fields : # extern crate juniper;\n# use juniper::graphql_object;\n#\nstruct Person; #[graphql_object]\n#[graphql(rename_all = \"none\")] // disables any renaming\nimpl Person { fn renamed_field( // exposed as `renamed_field` in GraphQL schema renamed_argument: bool, // exposed as `renamed_argument` in GraphQL schema ) -> bool { renamed_argument }\n}\n#\n# fn main() {} TIP : Supported policies are: SCREAMING_SNAKE_CASE, camelCase and none (disables any renaming).","breadcrumbs":"Type system » Objects » Complex fields » Renaming","id":"20","title":"Renaming"},"21":{"body":"Similarly, GraphQL fields may also be documented and deprecated via #[graphql(description = \"...\")] and #[graphql(deprecated = \"...\")]/ #[deprecated] attributes: # extern crate juniper;\n# use juniper::graphql_object;\n#\nstruct Person; /// This doc comment is visible only in Rust API docs.\n#[graphql_object]\n#[graphql(description = \"This description overwrites the one from doc comment.\")]\nimpl 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 }\n}\n#\n# fn main() {} NOTE : Only GraphQL object / interface fields and GraphQL enum values can be deprecated .","breadcrumbs":"Type system » Objects » Complex fields » Documentation and deprecation","id":"21","title":"Documentation and deprecation"},"22":{"body":"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)]\n# extern crate juniper;\n# use juniper::graphql_object;\n#\nstruct Person { name: String, age: i32,\n} #[graphql_object]\nimpl 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... }\n} impl Person { pub fn not_even_considered_for_graphql(&self) { // whatever goes... }\n}\n#\n# fn main() {} TIP : See more available features in the API docs of the #[graphql_object] attribute.","breadcrumbs":"Type system » Objects » Complex fields » Ignoring","id":"22","title":"Ignoring"},"23":{"body":"Context is a feature in Juniper that lets field resolvers access global data, most commonly database connections or authentication information. Let's say that we have a simple Users database in a HashMap: # #![allow(dead_code)]\n# use std::collections::HashMap;\n#\nstruct Database { users: HashMap ,\n} struct User { id: i32, name: String, friend_ids: Vec ,\n}\n#\n# fn main() {} We would like to define a friends field on User that returns a list of User objects . In order to write such a field we need to query a Database. To accomplish this we must first mark the Database as a valid context type and then assign it to the User object . To gain access to the context in the friends field , we need to specify an argument with the same type as the specified context: # extern crate juniper;\n# use std::collections::HashMap;\n# use juniper::graphql_object;\n#\nstruct Database { users: HashMap ,\n} // Mark the `Database` as a valid context type for Juniper.\nimpl juniper::Context for Database {} struct User { id: i32, name: String, friend_ids: Vec ,\n} #[graphql_object]\n#[graphql(context = Database)] // assign `Database` as the context type\nimpl User { // Inject the `Database` context by specifying an argument with the // context type: // - the type must be a reference; // - the name of the argument SHOULD be `context` (or `ctx`). fn friends<'db>(&self, context: &'db Database) -> Vec<&'db User> { // ^^^^^^^ or `ctx`, up to your preference self.friend_ids.iter() .map(|id| { context.users.get(&id).expect(\"could not find `User` with ID\") }) .collect() } fn friend<'db>( &self, id: i32, // Alternatively, the context argument may be marked with an attribute, // and thus, named arbitrary. #[graphql(context)] db: &'db Database, // ^^^^^^^ or `ctx`, up to your preference ) -> Option<&'db User> { self.friend_ids.contains(&id).then(|| { db.users.get(&id).expect(\"could not find `User` with ID\") }) } fn name(&self) -> &str { self.name.as_str() } fn id(&self) -> i32 { self.id }\n}\n#\n# fn main() {}","breadcrumbs":"Type system » Objects » Context » Context","id":"23","title":"Context"},"24":{"body":"Context cannot be a mutable reference as fields may be resolved concurrently. If something in the context requires a mutable reference, the context type should leverage the interior mutability pattern (e.g. use RwLock, RefCell or similar). For example, when using async runtime with work stealing (like tokio ), which obviously requires thread safety in addition, we will need to use a corresponding async version of RwLock: # extern crate juniper;\n# extern crate tokio;\n# use std::collections::HashMap;\n# use juniper::graphql_object;\nuse tokio::sync::RwLock; struct Database { requested_count: HashMap ,\n} // Since we cannot directly implement `juniper::Context`\n// for `RwLock`, we use the newtype idiom.\nstruct DatabaseContext(RwLock ); impl juniper::Context for DatabaseContext {} struct User { id: i32, name: String\n} #[graphql_object]\n#[graphql(context = DatabaseContext)]\nimpl User { async fn times_requested<'db>(&self, ctx: &'db DatabaseContext) -> i32 { // Acquire a mutable reference and `.await` if async `RwLock` is used, // which is necessary if context consists of async operations like // querying remote databases. // Obtain base type. let DatabaseContext(db) = ctx; // If context is immutable use `.read()` on `RwLock` instead. let mut db = db.write().await; // Perform a mutable operation. db.requested_count .entry(self.id) .and_modify(|e| *e += 1) .or_insert(1) .clone() } fn name(&self) -> &str { self.name.as_str() } fn id(&self) -> i32 { self.id }\n}\n#\n# fn main() {} TIP : Replace tokio::sync::RwLock with std::sync::RwLock (or similar) if you don't intend to use async resolving.","breadcrumbs":"Type system » Objects » Context » Mutating and mutable references","id":"24","title":"Mutating and mutable references"},"25":{"body":"Error handling in GraphQL can be done in multiple ways. We will cover the two different error handling models mostly used: Implicit field results . Explicit errors backend by GraphQL schema . Choosing the right error handling method depends on the requirements of the application and the concrete error happening. Investigating both approaches is beneficial.","breadcrumbs":"Type system » Objects » Error handling » Error handling","id":"25","title":"Error handling"},"26":{"body":"The first approach (where every error is a field error ) is easier to implement. However, clients won't know what errors may occur and instead will have to infer what happens from the error message . This is brittle and could change over time due to either clients or server changing. Therefore, extensive integration testing between clients and server is required to maintain the implicit contract between the two. Encoding non-critical errors in a GraphQL schema makes the contract between clients and the server explicit. This allows clients to understand and handle these errors correctly and the server to know when changes are potentially breaking clients. However, encoding this error information into a GraphQL schema requires additional code and up-front definition of non-critical errors.","breadcrumbs":"Type system » Objects » Error handling » Comparison","id":"26","title":"Comparison"},"27":{"body":"Rust provides two ways of dealing with errors : Result for recoverable errors; panic! for unrecoverable errors. Juniper does not do anything about panicking, it naturally bubbles up to the surrounding code/framework and can be dealt with there. For recoverable errors, Juniper works well with the built-in Result type . You can use the ? operator and things will work as you expect them to: # extern crate juniper;\n# use std::{fs::File, io::Read, path::PathBuf, str};\n# use juniper::{graphql_object, FieldResult};\n#\nstruct Example { filename: PathBuf,\n} #[graphql_object]\nimpl Example { fn contents(&self) -> FieldResult { let mut file = File::open(&self.filename)?; let mut contents = String::new(); file.read_to_string(&mut contents)?; Ok(contents) } fn foo() -> FieldResult