Expand description
GraphQL execution based on callbacks resolving one field at a time.
Start with Execution::new
,
then use builder-pattern methods to configure,
then use either the execute_sync
or execute_async
method.
They take an initial object value
(implementing the ObjectValue
or AsyncObjectValue
trait respectively)
that represents an instance of the root operation type (such as Query
).
Trait methods are called as needed to resolve object fields,
which may in turn return more objects.
How to implement the trait is up to the user: there could be a separate Rust struct per GraphQL object type, or a single Rust enum with a variants per GraphQL object type, or some other strategy.
§Example
use apollo_compiler::resolvers::AsyncObjectValue;
use apollo_compiler::resolvers::AsyncResolvedValue;
use apollo_compiler::resolvers::Execution;
use apollo_compiler::resolvers::FieldError;
use apollo_compiler::resolvers::ResolveInfo;
use apollo_compiler::ExecutableDocument;
use apollo_compiler::Schema;
use futures::future::BoxFuture;
async fn async_resolvers_example() {
let sdl = "
type Query {
field1: String
field2: [Int]
}
";
struct Query;
impl AsyncObjectValue for Query {
fn type_name(&self) -> &str {
"Query"
}
fn resolve_field<'a>(
&'a self,
info: &'a ResolveInfo<'a>,
) -> BoxFuture<'a, Result<AsyncResolvedValue<'a>, FieldError>> {
Box::pin(async move {
match info.field_name() {
"field1" => Ok(AsyncResolvedValue::leaf(self.resolve_field1().await)),
"field2" => Ok(AsyncResolvedValue::list(self.resolve_field2().await)),
_ => Err(self.unknown_field_error(info)),
}
})
}
}
impl Query {
async fn resolve_field1(&self) -> String {
// totally doing asynchronous I/O here
"string".into()
}
async fn resolve_field2(&self) -> [AsyncResolvedValue<'_>; 4] {
// very await
[7, 42, 0, 0].map(AsyncResolvedValue::leaf)
}
}
let query = "
query($skp: Boolean!) {
field1 @skip(if: $skp)
field2
}
";
let variables_values = &serde_json_bytes::json!({
"skp": false,
});
let schema = Schema::parse_and_validate(sdl, "schema.graphql").unwrap();
let document = ExecutableDocument::parse_and_validate(&schema, query, "query.graphql").unwrap();
let response = Execution::new(&schema, &document)
.raw_variable_values(variables_values.as_object().unwrap())
.execute_async(&Query)
.await
.unwrap();
let response = serde_json::to_string_pretty(&response).unwrap();
expect_test::expect![[r#"
{
"data": {
"field1": "string",
"field2": [
7,
42,
0,
0
]
}
}"#]]
.assert_eq(&response);
}
fn main() {
futures::executor::block_on(async_resolvers_example())
}
Structs§
- Execution
- Builder for configuring GraphQL execution
- Field
Error - An error returned by
ObjectValue::resolve_field
orAsyncObjectValue::resolve_field
, which will become a field error (a.k.a. execution error) in the GraphQL response, with path and locations filled in. - Resolve
Info - Information passed to
ObjectValue::resolve_field
orAsyncObjectValue::resolve_field
.
Enums§
- Async
Resolved Value - The successful return type of
AsyncObjectValue::resolve_field
. - Resolved
Value - The successful return type of
ObjectValue::resolve_field
.
Traits§
- Async
Object Value - A concrete GraphQL object whose fields can be resolved asynchronously during execution.
- Object
Value - A concrete GraphQL object whose fields can be resolved during execution.