### Integrate with Web Server (Examples) Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/quickstart.md Update the examples repository using `git submodule update` and run a specific example binary with `cargo run --bin [name]`. ```shell git submodule update # update the examples repo cd examples && cargo run --bin [name] ``` -------------------------------- ### Update Examples Sub-repository Source: https://github.com/async-graphql/async-graphql/blob/master/README.md Command to update the examples sub-repository for async-graphql. Ensure you have cloned the repository with submodules or run this command after cloning. ```shell git submodule update cd examples && cargo run --bin [name] ``` -------------------------------- ### Schema Execution Example Source: https://github.com/async-graphql/async-graphql/blob/master/src/docs/interface.md Build a schema with the defined interface and query type, execute a GraphQL query, and assert the result. This example demonstrates fetching data through the interface. ```rust struct Query; #[Object] impl Query { async fn type_a(&self) -> MyInterface { TypeA { value: 10 }.into() } } # tokio::runtime::Runtime::new().unwrap().block_on(async move { let schema = Schema::build(Query, EmptyMutation, EmptySubscription).data("hello".to_string()).finish(); let res = schema.execute(r#"{ typeA { valueA valueB valueC(a: 3, b: 2) value_d } }""#).await.into_result().unwrap().data; assert_eq!(res, value!(@{"typeA": {"valueA": "hello", "valueB": 10, "valueC": 5, "value_d": 11}})); # }); ``` -------------------------------- ### Middleware Function Example Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/extensions_inner_working.md Illustrates a basic middleware function structure, showing how to execute logic before or after calling the next middleware in the chain. ```rust async fn middleware(&self, ctx: &ExtensionContext<'_>, next: NextMiddleware<'_>) -> MiddlewareResult { // Logic to your middleware. /* * Final step to your middleware, we call the next function which will trigger * the execution of the next middleware. It's like a `callback` in JavaScript. */ next.run(ctx).await } ``` -------------------------------- ### GraphQL Query Example Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/dataloader.md A sample GraphQL query that can lead to the N+1 problem. ```graphql query { todos { users { name } } } ``` -------------------------------- ### Implement an Integer Stream Subscription Source: https://github.com/async-graphql/async-graphql/blob/master/docs/zh-CN/src/subscription.md This example demonstrates a subscription that emits integers every second. The `step` argument filters the emitted integers, defaulting to 1 if not provided. ```rust # extern crate async_graphql; # use std::time::Duration; # use async_graphql::futures_util::stream::Stream; # use async_graphql::futures_util::StreamExt; # extern crate tokio_stream; # extern crate tokio; use async_graphql::*; struct Subscription; #[Subscription] impl Subscription { async fn integers(&self, #[graphql(default = 1)] step: i32) -> impl Stream { let mut value = 0; tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(Duration::from_secs(1))) .map(move |_| { value += step; value }) } } ``` -------------------------------- ### Basic Error with Extensions Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/error_extensions.md This example shows how to create a basic error with custom extensions using `Error::new` and `extend_with`. ```rust use async_graphql::*; struct Query; #[Object] impl Query { async fn parse_with_extensions(&self) -> Result { Err(Error::new("MyMessage").extend_with(|_, e| e.set("details", "CAN_NOT_FETCH"))) } } ``` -------------------------------- ### Prepare Request Extension Implementation Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/extensions_inner_working.md Provides an example of the `prepare_request` extension hook, allowing modifications to the request before it's processed further. Logic can be placed before or after the `next.run` call. ```rust # extern crate async_graphql; # use async_graphql::*; # use async_graphql::*; # use async_graphql::extensions::*; # struct MyMiddleware; # #[async_trait::async_trait] # impl Extension for MyMiddleware { async fn prepare_request( &self, ctx: &ExtensionContext<'_>, request: Request, next: NextPrepareRequest<'_>, ) -> ServerResult { // The code here will be run before the prepare_request is executed, just after the request lifecycle hook. let result = next.run(ctx, request).await; // The code here will be run just after the prepare_request result } # } ``` -------------------------------- ### Registering DataLoader with Schema Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/dataloader.md Example of how to register a DataLoader with the GraphQL schema, specifying the task spawner. ```rust let schema = Schema::build(QueryRoot, EmptyMutation, EmptySubscription) .data(DataLoader::new( UserNameLoader, async_std::task::spawn, // or `tokio::spawn` )) .finish(); ``` -------------------------------- ### Build and Configure GraphQL Schema with async-graphql Source: https://context7.com/async-graphql/async-graphql/llms.txt Construct a GraphQL schema using `Schema::build` and chain configuration methods like `.data()`, `.limit_depth()`, `.limit_complexity()`, `.extension()`, and `.finish()` to produce an executable schema. This example demonstrates injecting global context values and applying security limits. ```rust use async_graphql::* use async_graphql::extensions::Logger; struct DbPool; struct Config { debug: bool } struct Query; #[Object] impl Query { async fn version(&self) -> &str { "1.0.0" } } struct Mutation; #[Object] impl Mutation { async fn noop(&self) -> bool { true } } let schema = Schema::build(Query, Mutation, EmptySubscription) // Inject global data accessible via ctx.data::() .data(DbPool) .data(Config { debug: true }) // Security: reject queries deeper than 10 levels .limit_depth(10) // Security: reject queries with more than 100 field selections .limit_complexity(100) // Middleware: log every request/response .extension(Logger) .finish(); // Execute a request programmatically let resp = futures::executor::block_on( schema.execute("{ version }") ); assert_eq!(resp.errors.len(), 0); ``` -------------------------------- ### Integrate GraphQL Schema with Actix-web HTTP Server Source: https://context7.com/async-graphql/async-graphql/llms.txt Wire the async-graphql schema into an Actix-web HTTP server. This example configures routes for GraphQL POST requests and WebSocket subscriptions. ```rust use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer}; use async_graphql::*; use async_graphql_actix_web::{GraphQLRequest, GraphQLResponse, GraphQLSubscription}; #[derive(Default, SimpleObject)] struct Query { version: String } type AppSchema = Schema; async fn graphql_handler( schema: web::Data, req: GraphQLRequest, ) -> web::Json { web::Json(schema.execute(req.into_inner()).await.into()) } async fn ws_handler( schema: web::Data, req: HttpRequest, payload: web::Payload, ) -> actix_web::Result { GraphQLSubscription::new(Schema::clone(&*schema)).start(&req, payload) } #[actix_web::main] async fn main() -> std::io::Result<()> { let schema = Schema::build(Query::default(), EmptyMutation, EmptySubscription).finish(); HttpServer::new(move || { App::new() .app_data(web::Data::new(schema.clone())) .route("/graphql", web::post().to(graphql_handler)) .route("/ws", web::get().to(ws_handler)) }) .bind("0.0.0.0:8000")?; .run() .await } ``` -------------------------------- ### Define a Subscription Resolver Source: https://github.com/async-graphql/async-graphql/blob/master/src/docs/subscription.md Implement a subscription resolver that returns a stream of values. This example streams integers from 0 up to a specified condition. ```rust use async_graphql::Subscription; use futures_util::stream::{Stream, StreamExt}; struct Subscription; #[Subscription] impl Subscription { async fn value(&self, condition: i32) -> impl Stream { // Returns the number from 0 to `condition`. futures_util::stream::iter(0..condition) } } ``` -------------------------------- ### Web Framework Integrations - Poem Source: https://context7.com/async-graphql/async-graphql/llms.txt Wire the async-graphql schema into an HTTP server using the Poem web framework. This example shows how to set up a GraphQL endpoint for POST requests and a WebSocket endpoint for subscriptions. ```APIDOC ### Poem ```rust use async_graphql::*; use async_graphql_poem::*; use poem::{get, listener::TcpListener, Route, Server}; #[derive(Default, SimpleObject)] struct Query { version: String } #[tokio::main] async fn main() -> Result<(), Box> { let schema = Schema::build(Query::default(), EmptyMutation, EmptySubscription).finish(); let app = Route::new() .at("/graphql", GraphQL::new(schema.clone())) // HTTP POST .at("/ws", get(GraphQLSubscription::new(schema))); // WebSocket Server::new(TcpListener::bind("0.0.0.0:8000")).run(app).await?; Ok(()) } ``` ``` -------------------------------- ### Deriving a Simple Object with a Field Source: https://github.com/async-graphql/async-graphql/blob/master/src/docs/simple_object.md Demonstrates how to derive a simple GraphQL object with a single field using the `SimpleObject` derive macro. This example shows basic schema creation and execution. ```rust use async_graphql::* #[derive(SimpleObject)] struct Query { value: i32, } tokio::runtime::Runtime::new().unwrap().block_on(async move { let schema = Schema::new(Query{ value: 10 }, EmptyMutation, EmptySubscription); let res = schema.execute("{ value }").await.into_result().unwrap().data; assert_eq!(res, value!({ "value": 10, })); }); ``` -------------------------------- ### Integrate GraphQL Schema with Poem HTTP Server Source: https://context7.com/async-graphql/async-graphql/llms.txt Wire the async-graphql schema into a Poem HTTP server. This example sets up a GraphQL endpoint for POST requests and a WebSocket endpoint for subscriptions. ```rust use async_graphql::*; use async_graphql_poem::*; use poem::{get, listener::TcpListener, Route, Server}; #[derive(Default, SimpleObject)] struct Query { version: String } #[tokio::main] async fn main() -> Result<(), Box> { let schema = Schema::build(Query::default(), EmptyMutation, EmptySubscription).finish(); let app = Route::new() .at("/graphql", GraphQL::new(schema.clone())) // HTTP POST .at("/ws", get(GraphQLSubscription::new(schema))); // WebSocket Server::new(TcpListener::bind("0.0.0.0:8000")).run(app).await?; Ok(()) } ``` -------------------------------- ### Define and Merge Multiple Subscription Types Source: https://github.com/async-graphql/async-graphql/blob/master/src/docs/merged_subscription.md This example demonstrates how to define two separate subscription types, `Subscription1` and `Subscription2`, each with its own asynchronous stream of events. The `MergedSubscription` derive macro is then used to combine these into a single `Subscription` type, which can be used in the GraphQL schema. ```rust use async_graphql::* use futures_util::stream::Stream; #[derive(Default)] struct Subscription1; #[Subscription] impl Subscription1 { async fn events1(&self) -> impl Stream { futures_util::stream::iter(0..10) } } #[derive(Default)] struct Subscription2; #[Subscription] impl Subscription2 { async fn events2(&self) -> impl Stream { futures_util::stream::iter(10..20) } } #[derive(MergedSubscription, Default)] struct Subscription(Subscription1, Subscription2); ``` -------------------------------- ### Define Subscription Root Object Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/subscription.md Defines a subscription root object with an integer stream resolver. The `step` parameter filters the stream, defaulting to 1. This example generates an integer per second. ```rust # extern crate async_graphql; # use std::time::Duration; # use async_graphql::futures_util::stream::Stream; # use async_graphql::futures_util::StreamExt; # extern crate tokio_stream; # extern crate tokio; use async_graphql::* struct Subscription; #[Subscription] impl Subscription { async fn integers(&self, #[graphql(default = 1)] step: i32) -> impl Stream { let mut value = 0; tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(Duration::from_secs(1))) .map(move |_| { value += step; value }) } } ``` -------------------------------- ### Deriving Fields for Wrapper Types with Custom Logic Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/derived_fields.md This example shows how to derive a field for an `Option` wrapper type when a direct `From` implementation is not possible due to Rust's orphan rules. It utilizes the `with` parameter in the `#[graphql(derived(...))]` attribute to specify a custom function (`option_to_option`) for handling the transformation. ```rust # extern crate serde; # use serde::{Serialize, Deserialize}; # extern crate async_graphql; # use async_graphql::*; #[derive(Serialize, Deserialize, Clone)] struct ValueDerived(String); #[derive(Serialize, Deserialize, Clone)] struct ValueDerived2(String); scalar!(ValueDerived); scalar!(ValueDerived2); impl From for ValueDerived2 { fn from(value: ValueDerived) -> Self { ValueDerived2(value.0) } } fn option_to_option>(value: Option) -> Option { value.map(|x| x.into()) } #[derive(SimpleObject)] struct TestObj { #[graphql(derived(owned, name = "value2", into = "Option", with = "option_to_option"))] pub value1: Option, } ``` -------------------------------- ### Run Benchmarks Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/introduction.md Execute the benchmark tests for Async-graphql. Ensure no CPU-heavy processes are running in the background. A HTML report will be generated upon completion. ```shell cd benchmark carqo bench ``` -------------------------------- ### Build Static GraphQL Schema with Poem Source: https://github.com/async-graphql/async-graphql/blob/master/README.md Sets up a basic GraphQL server with a static schema using async-graphql and the Poem web framework. Includes GraphiQL integration for testing. ```rust use std::error::Error; use async_graphql::{http::GraphiQLSource, EmptyMutation, EmptySubscription, Object, Schema}; use async_graphql_poem::* use poem::{listener::TcpListener, web::Html, *}; struct Query; #[Object] impl Query { async fn howdy(&self) -> &'static str { "partner" } } #[handler] async fn graphiql() -> impl IntoResponse { Html(GraphiQLSource::build().finish()) } #[tokio::main] async fn main() -> Result<(), Box> { // create the schema let schema = Schema::build(Query, EmptyMutation, EmptySubscription).finish(); // start the http server let app = Route::new().at("/", get(graphiql).post(GraphQL::new(schema))); println!("GraphiQL: http://localhost:8000"); Server::new(TcpListener::bind("0.0.0.0:8000")) .run(app) .await?; Ok(()) } ``` -------------------------------- ### User Resolver Causing N+1 Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/dataloader.md An example of a User resolver that performs a separate database query for each user, leading to the N+1 problem. ```rust struct User { id: u64, } #[Object] impl User { async fn name(&self, ctx: &Context<'_>) -> Result { let pool = ctx.data_unchecked::>(); let (name,): (String,) = sqlx::query_as("SELECT name FROM user WHERE id = $1") .bind(self.id) .fetch_one(pool) .await?; Ok(name) } } ``` -------------------------------- ### Request Extension with Pre and Post Logic Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/extensions_inner_working.md Demonstrates how to add logic before and after the `next.run` call within the `request` extension hook to control execution order. ```rust # extern crate async_graphql; # use async_graphql::*; # use async_graphql::extensions::*; # struct MyMiddleware; # #[async_trait::async_trait] # impl Extension for MyMiddleware { async fn request(&self, ctx: &ExtensionContext<'_>, next: NextRequest<'_>) -> Response { // The code here will be run before the prepare_request is executed. let result = next.run(ctx).await; // The code after the completion of this future will be after the processing, just before sending the result to the user. result } # } ``` -------------------------------- ### GraphQL Schema with @requires Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/apollo_federation.md An example GraphQL schema for a `Product` type that uses the `@external` directive for `size` and `weightInPounds`, and the `@requires` directive for `shippingEstimate`. ```APIDOC type Product @key(fields: "id") { id: ID! size: Int! @external weightInPounds: Int! @external shippingEstimate: String! @requires(fields: "size weightInPounds") } ``` -------------------------------- ### Implement Extension Execution Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/extensions_inner_working.md Called at execute query. Use this to perform actions before or after query execution. ```rust # extern crate async_graphql; # use async_graphql::*; # use async_graphql::extensions::*; # struct MyMiddleware; # #[async_trait::async_trait] # impl Extension for MyMiddleware { /// Called at execute query. async fn execute( &self, ctx: &ExtensionContext<'_>, operation_name: Option<&str>, next: NextExecute<'_>, ) -> Response { // Before starting resolving the whole query let result = next.run(ctx, operation_name).await; // After resolving the whole query result # } # } ``` -------------------------------- ### Define Mutation Root Object Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/query_and_mutation.md Defines a Mutation root object where operations are executed sequentially. This example includes signup and login mutations. ```rust extern crate async_graphql; use async_graphql::*; struct Mutation; #[Object] impl Mutation { async fn signup(&self, username: String, password: String) -> Result { // User signup todo!() } async fn login(&self, username: String, password: String) -> Result { // User login (generate token) todo!() } } ``` -------------------------------- ### Generated Schema with Type System Directive Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/custom_directive.md Example of a GraphQL schema generated with a custom type system directive applied to a type and its field. ```graphql type SimpleValue @testDirective(scope: "simple object type", input: 1, opt: 3) { someData: String! @testDirective(scope: "field and param with \" symbol", input: 2, opt: 3) } directive @testDirective(scope: String!, input: Int!, opt: Int) on FIELD_DEFINITION | OBJECT ``` -------------------------------- ### Build Dynamic GraphQL Schema with Poem Source: https://github.com/async-graphql/async-graphql/blob/master/README.md Demonstrates creating a GraphQL server with a dynamic schema using async-graphql and Poem. This approach allows for schema definition at runtime. Requires the 'dynamic-schema' feature. ```rust use std::error::Error; use async_graphql::{dynamic::*, http::GraphiQLSource}; use async_graphql_poem::* use poem::{listener::TcpListener, web::Html, *}; #[handler] async fn graphiql() -> impl IntoResponse { Html(GraphiQLSource::build().finish()) } #[tokio::main] async fn main() -> Result<(), Box> { let query = Object::new("Query").field(Field::new( "howdy", TypeRef::named_nn(TypeRef::STRING), |_| FieldFuture::new(async { "partner" }), )); // create the schema let schema = Schema::build(query, None, None).register(query).finish()?; // start the http server let app = Route::new().at("/", get(graphiql).post(GraphQL::new(schema))); println!("GraphiQL: http://localhost:8000"); Server::new(TcpListener::bind("0.0.0.0:8000")) .run(app) .await?; Ok(()) } ``` -------------------------------- ### Rust Implementation with #[graphql(provides)] Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/apollo_federation.md Rust code demonstrating how to implement the `outOfStockProducts` query using async-graphql, with the `#[graphql(provides = "humanName")]` attribute to signify that the `human_name` field is provided. ```APIDOC # use async_graphql::* #[derive(SimpleObject)] struct Product { id: ID, #[graphql(external)] human_name: String, in_stock: bool, } struct Query; #[Object] impl Query { /// This operation will provide the `humanName` field on `Product #[graphql(provides = "humanName")] async fn out_of_stock_products(&self) -> Vec { vec![Product { id: "1".into(), human_name: "My Product".to_string(), in_stock: false, }] } async fn discontinued_products(&self) -> Vec { vec![Product { id: "2".into(), human_name: String::new(), // This is ignored by the router in_stock: false, }] } #[graphql(entity)] async fn find_product_by_id(&self, id: ID) -> Product { Product { id, human_name: String::new(), // This is ignored by the router in_stock: true, } } } ``` -------------------------------- ### Execute GraphQL Query Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/quickstart.md Create a schema instance with Query, Mutation, and Subscription types, then use `Schema::execute` to run a GraphQL query. ```rust # extern crate async_graphql; # use async_graphql::*; # # struct Query; # #[Object] # impl Query { # async fn version(&self) -> &str { "1.0" } # } # async fn other() { let schema = Schema::new(Query, EmptyMutation, EmptySubscription); let res = schema.execute("{ add(a: 10, b: 20) }").await; # } ``` -------------------------------- ### Custom Validator for Integer Input Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/input_value_validators.md Implement the `CustomValidator` trait to create your own validation logic. This example ensures an integer input `n` is exactly equal to 100. ```rust use async_graphql::*; struct MyValidator { expect: i32, } impl MyValidator { pub fn new(n: i32) -> Self { MyValidator { expect: n } } } impl CustomValidator for MyValidator { fn check(&self, value: &i32) -> Result<(), InputValueError> { if *value == self.expect { Ok(()) } else { Err(InputValueError::custom(format!("expect 100, actual {}", value))) } } } struct Query; #[Object] impl Query { /// n must be equal to 100 async fn value( &self, #[graphql(validator(custom = "MyValidator::new(100)"))] n: i32, ) -> i32 { n } } ``` -------------------------------- ### Interface Definition Without Direct Schema Reference Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/define_interface.md Defines a `MyInterface` and `MyObject`. This example demonstrates a scenario where the interface might not be automatically registered if not referenced in the schema. ```rust extern crate async_graphql; # use async_graphql::*; #[derive(Interface)] #[graphql( field(name = "name", ty = "String"), )] enum MyInterface { MyObject(MyObject), } #[derive(SimpleObject)] struct MyObject { name: String, } struct Query; #[Object] impl Query { async fn obj(&self) -> MyObject { todo!() } } type MySchema = Schema; ``` -------------------------------- ### Example of an Expensive GraphQL Query Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/depth_and_complexity.md This query demonstrates how a deeply nested request for related posts can exponentially increase response size, potentially leading to performance issues. ```graphql { posts(count: 100) { related(count: 100) { related(count: 100) { related(count: 100) { title } } } } } ``` -------------------------------- ### Add Async-GraphQL Dependencies Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/quickstart.md Add the necessary async-graphql and integration libraries to your Cargo.toml file. ```toml [dependencies] async-graphql = "4.0" async-graphql-actix-web = "4.0" # If you need to integrate into actix-web async-graphql-warp = "4.0" # If you need to integrate into warp ``` -------------------------------- ### Inspecting Requested Fields with LookAhead Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/context.md Demonstrates how to use `ctx.look_ahead()` to inspect the fields requested in a subquery. This allows for conditional logic based on which fields are being queried, enabling optimizations. ```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!() } } ``` -------------------------------- ### Enable Apollo Tracing Extension Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/apollo_tracing.md Add the ApolloTracing extension when building the schema to enable performance analysis for each query step. ```rust extern crate async_graphql; use async_graphql::*; use async_graphql::extensions::ApolloTracing; struct Query; #[Object] impl Query { async fn version(&self) -> &str { "1.0" } } let schema = Schema::build(Query, EmptyMutation, EmptySubscription) .extension(ApolloTracing) // Enable ApolloTracing extension .finish(); ``` -------------------------------- ### Export GraphQL Schema as SDL Source: https://context7.com/async-graphql/async-graphql/llms.txt Obtain the full human-readable Schema Definition Language (SDL) string for documentation or federation composition by calling `schema.sdl()`. ```rust use async_graphql::*; #[derive(SimpleObject)] struct Book { title: String, author: String } struct Query; #[Object] impl Query { async fn books(&self) -> Vec { vec![] } async fn add(&self, a: i32, b: i32) -> i32 { a + b } } let schema = Schema::build(Query, EmptyMutation, EmptySubscription).finish(); let sdl = schema.sdl(); println!("{}", sdl); // Output: // type Book { title: String!, author: String! } // type Query { books: [Book!]!, add(a: Int!, b: Int!): Int! } // schema { query: Query } ``` -------------------------------- ### Define a Union Type Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/define_union.md Define a union type by deriving `Union` on an enum. Each enum variant represents a possible object type in the union. This example shows a `Shape` union with `Circle` and `Square` members. ```rust extern crate async_graphql; use async_graphql::*; struct Circle { radius: f32, } #[Object] impl Circle { async fn area(&self) -> f32 { std::f32::consts::PI * self.radius * self.radius } async fn scale(&self, s: f32) -> Shape { Circle { radius: self.radius * s }.into() } } struct Square { width: f32, } #[Object] impl Square { async fn area(&self) -> f32 { self.width * self.width } async fn scale(&self, s: f32) -> Shape { Square { width: self.width * s }.into() } } #[derive(Union)] enum Shape { Circle(Circle), Square(Square), } ``` -------------------------------- ### Cursor Connections (Relay-compliant pagination) Source: https://context7.com/async-graphql/async-graphql/llms.txt Implement Relay-compliant pagination using `connection::query()`. This handles `after`, `before`, `first`, and `last` arguments, returning a `Connection` object with edges and page info. ```APIDOC ## Cursor Connections — Relay-compliant pagination Use `connection::query()` inside a resolver to implement the full Relay Cursor Connections specification with `after`, `before`, `first`, `last` arguments. Returns a `Connection` with `edges`, `pageInfo`, and optional extra fields. ```rust use async_graphql::*; use async_graphql::types::connection::*; const MAX_ITEMS: usize = 1000; struct Query; #[Object] impl Query { async fn numbers( &self, after: Option, before: Option, first: Option, last: Option, ) -> Result> { query(after, before, first, last, |after, before, first, last| async move { let mut start = after.map(|a| a + 1).unwrap_or(0); let mut end = before.unwrap_or(MAX_ITEMS); if let Some(first) = first { end = (start + first).min(end); } if let Some(last) = last { start = if last > end - start { end } else { end - last }; } let mut conn = Connection::new(start > 0, end < MAX_ITEMS); conn.edges.extend((start..end).map(|n| Edge::new(n, n as i32))); Ok::<_, Error>(conn) }).await } } // GraphQL: { numbers(first: 3, after: "4") { edges { cursor node } pageInfo { hasNextPage } } } // => edges with nodes [5,6,7], pageInfo.hasNextPage: true ``` ``` -------------------------------- ### Define a OneofObject with Enum Variants Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/define_one_of_object.md Define a OneofObject using an enum where each variant holds a different input type, including other InputObjects. This example shows searching users by email, registration number, or address. ```rust use async_graphql::* #[derive(OneofObject)] enum UserBy { Email(String), RegistrationNumber(i64), Address(Address) } #[derive(InputObject)] struct Address { street: String, house_number: String, city: String, zip: String, } struct Query {} #[Object] impl Query { async fn search_users(&self, by: Vec) -> Vec { // ... Searches and returns a list of users ... todo!() } } ``` -------------------------------- ### Inserting and Appending HTTP Headers Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/context.md Shows how to insert and append HTTP headers to the response context. `insert_http_header` overwrites existing headers with the same key, while `append_http_header` adds a new header with the same key. ```rust use async_graphql::*; use ::http::header::ACCESS_CONTROL_ALLOW_ORIGIN; struct Query; #[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.append_http_header("Custom-Header", "Hello World"); String::from("Hello world") } } ``` -------------------------------- ### Execute Extension Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/extensions_inner_working.md The `execute` step is responsible for initiating the query execution. It handles concurrent execution for Queries and serial execution for Mutations. ```APIDOC ## execute ### Description Called at execute query. This step starts the execution of the query by calling each resolver concurrently for a `Query` and serially for a `Mutation`. ### Method `async fn execute(&self, ctx: &ExtensionContext<'_>, operation_name: Option<&str>, next: NextExecute<'_>) -> Response` ### Parameters #### Path Parameters None #### Query Parameters * **operation_name** (Option<&str>) - Optional name of the operation to execute. #### Request Body None ### Request Example None ### Response #### Success Response (200) `Response` #### Response Example None ``` -------------------------------- ### Implement and Use Concat Directive Source: https://github.com/async-graphql/async-graphql/blob/master/src/docs/directive.md This snippet shows how to define a custom directive 'concat' that appends a given string value to the result of a field. It includes the directive implementation, its registration with the schema, and an example query demonstrating its usage. ```rust use async_graphql::*; struct ConcatDirective { value: String, } #[async_trait::async_trait] impl CustomDirective for ConcatDirective { async fn resolve_field(&self, _ctx: &Context<'_>, resolve: ResolveFut<'_>) -> ServerResult> { resolve.await.map(|value| { value.map(|value| match value { Value::String(str) => Value::String(str + &self.value), _ => value, }) }) } } #[Directive(location = "Field")] fn concat(value: String) -> impl CustomDirective { ConcatDirective { value } } struct Query; #[Object] impl Query { async fn value(&self) -> &'static str { "abc" } } tokio::runtime::Runtime::new().unwrap().block_on(async move { let schema = Schema::build(Query, EmptyMutation, EmptySubscription) .directive(concat) .finish(); let res = schema.execute(r#"{ value @concat(value: \"def\") }"#).await.into_result().unwrap().data; assert_eq!(res, value!({ "value": "abcdef", })); }); ``` -------------------------------- ### Implement Custom Scalar Type Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/custom_scalars.md Define a custom scalar type by implementing the `ScalarType` trait. This example shows a 64-bit integer scalar that uses strings for input and output. Ensure parsing logic handles potential errors. ```rust # extern crate async_graphql; use async_graphql::*; struct StringNumber(i64); #[Scalar] impl ScalarType for StringNumber { fn parse(value: Value) -> InputValueResult { if let Value::String(value) = &value { // Parse the integer value Ok(value.parse().map(StringNumber)?) } else { // If the type does not match Err(InputValueError::expected_type(value)) } } fn to_value(&self) -> Value { Value::String(self.0.to_string()) } } ``` -------------------------------- ### Apply RoleGuard to Object Fields Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/field_guard.md Use the `#[graphql(guard = "...")]` attribute on fields to apply guards. This example shows how to restrict access to fields based on user roles, including combining multiple guards with `.or()`. ```rust extern crate async_graphql; use async_graphql::*; #[derive(Eq, PartialEq, Copy, Clone)] enum Role { Admin, Guest, } struct RoleGuard { role: Role, } impl RoleGuard { fn new(role: Role) -> Self { Self { role } } } impl Guard for RoleGuard { async fn check(&self, ctx: &Context<'_>) -> Result<()> { todo!() } } #[derive(SimpleObject)] struct Query { /// Only allow Admin #[graphql(guard = "RoleGuard::new(Role::Admin)")] value1: i32, /// Allow Admin or Guest #[graphql(guard = "RoleGuard::new(Role::Admin).or(RoleGuard::new(Role::Guest))")] value2: i32, } ``` -------------------------------- ### Actix-web GraphQL Subscription Handler Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/integrations_to_actix_web.md Set up a WebSocket endpoint for GraphQL subscriptions using `GraphQLSubscription`. Requires an HttpRequest and Payload. ```rust # extern crate async_graphql_actix_web; # extern crate async_graphql; # extern crate actix_web; # use async_graphql::* # #[derive(Default,SimpleObject)] # struct Query { a: i32 } # let schema = Schema::build(Query::default(), EmptyMutation, EmptySubscription).finish(); use actix_web::{web, HttpRequest, HttpResponse}; use async_graphql_actix_web::GraphQLSubscription; async fn index_ws( schema: web::Data>, req: HttpRequest, payload: web::Payload, ) -> actix_web::Result { GraphQLSubscription::new(Schema::clone(&*schema)).start(&req, payload) } ``` -------------------------------- ### Implement Custom Scalar Type Source: https://context7.com/async-graphql/async-graphql/llms.txt Implement `ScalarType` manually for full control over parsing and serialization, or use the `scalar!` macro for types that already implement `serde::Serialize`/`Deserialize`. This example shows a 64-bit integer transmitted as a JSON string to avoid JS precision loss. ```rust use async_graphql::* /// A 64-bit integer transmitted as a JSON string to avoid JS precision loss struct StringInt(i64); #[Scalar] impl ScalarType for StringInt { fn parse(value: Value) -> InputValueResult { match value { Value::String(s) => s.parse::() .map(StringInt) .map_err(InputValueError::custom), other => Err(InputValueError::expected_type(other)), } } fn to_value(&self) -> Value { Value::String(self.0.to_string()) } } #[derive(SimpleObject)] struct LargeCounter { count: StringInt, } struct Query; #[Object] impl Query { async fn counter(&self) -> LargeCounter { LargeCounter { count: StringInt(9_007_199_254_740_993_i64) } } } // GraphQL: { counter { count } } // => { "counter": { "count": "9007199254740993" } } ``` -------------------------------- ### `#[Object]` - Define resolvers manually with full async support and context access Source: https://context7.com/async-graphql/async-graphql/llms.txt This macro allows manual definition of resolvers for GraphQL fields. Each field in the `impl` block must have an async resolver. The first argument is `&self`, an optional second argument `ctx: &Context<'_>` provides access to shared data and HTTP headers, and additional arguments become GraphQL field arguments. Fallible resolvers should return `Result`. ```APIDOC ## `#[Object]` — Define resolvers manually with full async support and context access Every field on the impl block must have an async resolver. The first argument is always `&self`; an optional second argument `ctx: &Context<'_>` provides access to shared data, HTTP headers, and look-ahead. Additional arguments become GraphQL field arguments. Return `Result` for fallible resolvers. ```rust use async_graphql::*; struct DbPool; // placeholder impl DbPool { async fn find_user(&self, id: i64) -> Option { Some(format!("user_{}", id)) } } struct Query; #[Object] impl Query { /// Returns a user name by ID; reads the DB pool from context async fn user( &self, ctx: &Context<'_>, #[graphql(desc = "User ID to look up")] id: i64, ) -> Result> { let pool = ctx.data::()?; Ok(pool.find_user(id).await) } } // Attach the pool when building the schema let schema = Schema::build(Query, EmptyMutation, EmptySubscription) .data(DbPool) .finish(); // GraphQL: { user(id: 42) } // => { "user": "user_42" } ``` ``` -------------------------------- ### Splitting Root Objects to Avoid Query Depth Limits Source: https://github.com/async-graphql/async-graphql/blob/master/src/docs/merged_object.md When facing compilation errors related to query depth limits, split the root object into smaller sets merged with `MergedObject`. This example demonstrates merging `Object1` and `Object2` into `MergeSet1`, and then merging `MergeSet1` with `Object3` into `RootObject`. ```rust use async_graphql::*; #[derive(SimpleObject)] struct Object1 { a: i32, } #[derive(SimpleObject)] struct Object2 { b: i32, } #[derive(SimpleObject)] struct Object3 { c: i32, } #[derive(MergedObject)] struct MergeSet1(Object1, Object2); #[derive(MergedObject)] struct RootObject(MergeSet1, Object3); let obj = RootObject(MergeSet1(Object1 { a: 10 }, Object2 { b: 20}), Object3 { c: 30}); ``` -------------------------------- ### Export Schema to SDL Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/sdl_export.md Use the `Schema::sdl()` method to print your schema in Schema Definition Language (SDL) format. Ensure your schema is built and finalized before calling this method. ```rust # extern crate async_graphql; use async_graphql::* struct Query; #[Object] impl Query { async fn add(&self, u: i32, v: i32) -> i32 { u + v } } let schema = Schema::build(Query, EmptyMutation, EmptySubscription).finish(); // Print the schema in SDL format println!("{}", &schema.sdl()); ``` -------------------------------- ### Protect Fields with Authorization Guards Source: https://context7.com/async-graphql/async-graphql/llms.txt Implement the `Guard` trait and attach guards to fields via `#[graphql(guard = "...")]`. Guards are checked before the resolver runs; combine multiple guards with `.and()` / `.or()`. This example demonstrates requiring specific roles for field access. ```rust use async_graphql::* #[derive(Eq, PartialEq, Clone)] enum Role { Admin, User } struct RequireRole(Role); impl Guard for RequireRole { async fn check(&self, ctx: &Context<'_>) -> Result<()> { match ctx.data_opt::() { Some(role) if role == &self.0 => Ok(()), _ => Err("Forbidden: insufficient permissions".into()), } } } struct Query; #[Object] impl Query { /// Only accessible by admins #[graphql(guard = "RequireRole(Role::Admin)")] async fn admin_dashboard(&self) -> String { "secret admin data".to_string() } /// Accessible by admin OR regular user #[graphql(guard = "RequireRole(Role::Admin).or(RequireRole(Role::User))")] async fn profile(&self) -> String { "user profile".to_string() } } // Attach the role when processing the request: // schema.execute(request.data(Role::Admin)).await ``` -------------------------------- ### Define a GraphQL Union Source: https://github.com/async-graphql/async-graphql/blob/master/src/docs/union.md Define union members as separate structs and then combine them into a union enum. This allows a field to return one of several possible object types. The example demonstrates returning a vector of union types from a query and querying specific fields based on the concrete type. ```rust use async_graphql::*; #[derive(SimpleObject)] struct TypeA { value_a: i32, } #[derive(SimpleObject)] struct TypeB { value_b: i32 } #[derive(Union)] enum MyUnion { TypeA(TypeA), TypeB(TypeB), } struct Query; #[Object] impl Query { async fn all_data(&self) -> Vec { vec![TypeA { value_a: 10 }.into(), TypeB { value_b: 20 }.into()] } } # tokio::runtime::Runtime::new().unwrap().block_on(async move { let schema = Schema::build(Query, EmptyMutation, EmptySubscription).data("hello".to_string()).finish(); let res = schema.execute(r#" { allData { ... on TypeA { valueA } ... on TypeB { valueB } } }"#).await.into_result().unwrap().data; assert_eq!(res, value!({ "allData": [ { "valueA": 10 }, { "valueB": 20 }, ] })); # }); ``` -------------------------------- ### Implementing Multiple Data Types for Loader Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/dataloader.md Shows how a single loader can be used to fetch multiple distinct data types. ```rust # extern crate async_graphql; # use async_graphql::* struct PostgresLoader { pool: sqlx::PgPool, } impl Loader for PostgresLoader { type Value = User; type Error = Arc; async fn load(&self, keys: &[UserId]) -> Result, Self::Error> { // Load users from database } } impl Loader for PostgresLoader { type Value = Todo; type Error = sqlx::Error; async fn load(&self, keys: &[TodoId]) -> Result, Self::Error> { // Load todos from database } } ``` -------------------------------- ### Optimized SQL Queries Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/dataloader.md Demonstrates the reduced number of SQL queries after implementing DataLoader. ```sql SELECT id, todo, user_id FROM todo SELECT name FROM user WHERE id IN (1, 2, 3, 4) ``` -------------------------------- ### Deriving a New Field with Different Output Type Source: https://github.com/async-graphql/async-graphql/blob/master/docs/en/src/derived_fields.md This example demonstrates how to derive a new field `date_rfc3339` from an existing field `date_rfc2822` using the `#[graphql(derived(...))]` attribute. It shows the definition of custom scalar types for different date formats and the implementation of the `From` trait for type conversion. ```rust # extern crate chrono; # use chrono::Utc; # extern crate async_graphql; # use async_graphql::*; struct DateRFC3339(chrono::DateTime); struct DateRFC2822(chrono::DateTime); #[Scalar] impl ScalarType for DateRFC3339 { fn parse(value: Value) -> InputValueResult { todo!() } fn to_value(&self) -> Value { Value::String(self.0.to_rfc3339()) } } #[Scalar] impl ScalarType for DateRFC2822 { fn parse(value: Value) -> InputValueResult { todo!() } fn to_value(&self) -> Value { Value::String(self.0.to_rfc2822()) } } impl From for DateRFC3339 { fn from(value: DateRFC2822) -> Self { DateRFC3339(value.0) } } struct Query; #[Object] impl Query { #[graphql(derived(name = "date_rfc3339", into = "DateRFC3339"))] async fn date_rfc2822(&self, arg: String) -> DateRFC2822 { todo!() } } ```