From 3fa4d55d07e111ba33ef26a8720e061f8212d3e2 Mon Sep 17 00:00:00 2001 From: Miaxos Date: Tue, 31 Aug 2021 13:54:35 +0000 Subject: [PATCH] misc: add some documentation about context --- docs/en/src/context.md | 114 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/docs/en/src/context.md b/docs/en/src/context.md index d1921302..af30819f 100644 --- a/docs/en/src/context.md +++ b/docs/en/src/context.md @@ -1,6 +1,16 @@ # Context -The main goal of `Context` is to acquire global data attached to Schema. **Note that if the return value of resolver function is borrowed from `Context`, you will need to explicitly state the lifetime of the argument.** +The main goal of `Context` is to acquire global data attached to Schema and also data related to the actual query being processed. + +## Store Data + +Inside the `Context` you can put global data, like environnement variables, db connection pool, whatever you may need in every query. + +The data must implement `Send` and `Sync`. + +You can request the data inside a query by just calling `ctx.data::()`. + +**Note that if the return value of resolver function is borrowed from `Context`, you will need to explicitly state the lifetime of the argument.** The following example shows how to borrow data in `Context`. @@ -19,3 +29,105 @@ impl Query { } } ``` + +### Schema data + +You can put data inside the context at the creation of the schema, it's usefull for data that do not change, like a connection pool. + +An instance of how it would be written inside an application: +```rust + let schema = Schema::build(Query::default(), Mutation::default(), EmptySubscription) + .data(env_struct) + .data(s3_storage) + .data(db_core) +``` + +### Request data + +You can put data inside the context at the execution of the request, it's usefull for authentification data for instance. + +A little example with a `warp` route: + +```rust +let graphql_post = warp::post() + .and(warp::path("graphql")) + .and(schema_filter) + .and(a_warp_filter) + ... + .and_then( |schema: (Schema, async_graphql::Request), arg2: ArgType2 ...| async move { + let (schema, request) = schema; + let your_auth_data = auth_function_from_headers(headers).await?; + let response = schema + .execute( + request + .data(your_auth_data) + .data(something_else) + ).await; + + Ok(async_graphql_warp::Response::from(response)) + }); +``` + + +## Headers + +With the Context you can also insert and appends headers. + +```rust +#[Object] +impl Query { + async fn greet(&self, ctx: &Context<'_>) -> String { + // Headers can be inserted using the `http` constants + let was_in_headers = ctx.insert_http_header(ACCESS_CONTROL_ALLOW_ORIGIN, "*"); + + // They can also be inserted using &str + let was_in_headers = ctx.insert_http_header("Custom-Header", "1234"); + + // If multiple headers with the same key are `inserted` then the most recent + // one overwrites the previous. If you want multiple headers for the same key, use + // `append_http_header` for subsequent headers + let was_in_headers = ctx.insert_http_header("Custom-Header", "Hello World"); + + String::from("Hello world") + } +} +``` + +## Selection / LookAhead + +Sometimes you want to know what fields are requested in the subquery to optimize the processing of data. You can read fields accross the query with `ctx.fields()` which will give you a `SelectionField` which will allow you to navigate accross the fields and subfields. + +If you want to perform a search accross the query or the subqueries, you do not have to do this by hand with the `SelectionField`, you can use the `ctx.look_ahead()` to perform a selection + +```rust +use async_graphql::*; + +#[derive(SimpleObject)] +struct Detail { + c: i32, + d: i32, +} + +#[derive(SimpleObject)] +struct MyObj { + a: i32, + b: i32, + detail: Detail, +} + +struct Query; + +#[Object] +impl Query { + async fn obj(&self, ctx: &Context<'_>) -> MyObj { + if ctx.look_ahead().field("a").exists() { + // This is a query like `obj { a }` + } else if ctx.look_ahead().field("detail").field("c").exists() { + // This is a query like `obj { detail { c } }` + } else { + // This query doesn't have `a` + } + unimplemented!() + } +} +```