//! # A GraphQL server library implemented in Rust //! //!
//! //! //! //! //! //! //! Crates.io version //! //! //! //! Download //! //! //! //! docs.rs docs //! //! //! Unsafe Rust forbidden //! //!
//! //! ## Documentation //! //! * [Feature Comparison](feature-comparison.md) //! * [Book](https://async-graphql.github.io/async-graphql/en/index.html) //! * [中文文档](https://async-graphql.github.io/async-graphql/zh-CN/index.html) //! * [Docs](https://docs.rs/async-graphql) //! * [GitHub repository](https://github.com/async-graphql/async-graphql) //! * [Cargo package](https://crates.io/crates/async-graphql) //! * Minimum supported Rust version: 1.42 or later //! //! ## Features //! //! * Fully supports async/await //! * Type safety //! * Rustfmt friendly (Procedural Macro) //! * Custom scalars //! * Minimal overhead //! * Easy integration (actix_web, tide, warp, rocket ...) //! * File upload (Multipart request) //! * Subscriptions (WebSocket transport) //! * Custom extensions //! * Apollo Tracing extension //! * Limit query complexity/depth //! * Error Extensions //! * Apollo Federation //! * Batch Queries //! * Apollo Persisted Queries //! //! # Crate features //! //! This crate offers the following features, all of which are activated by default: //! //! - `apollo_tracing`: Enable the [Apollo tracing extension](extensions/struct.ApolloTracing.html). //! - `apollo_persisted_queries`: Enable the [Apollo persisted queries extension](extensions/apollo_persisted_queries/struct.ApolloPersistedQueries.html). //! - `log`: Enable the [logger extension](extensions/struct.Logger.html). //! - `tracing`: Enable the [tracing extension](extensions/struct.Tracing.html). //! - `multipart`: Support [sending files over HTTP multipart](http/fn.receive_body.html). //! - `unblock`: Support [asynchronous reader for Upload](types/struct.Upload.html) //! - `bson`: Integrate with the [`bson` crate](https://crates.io/crates/bson). //! - `chrono`: Integrate with the [`chrono` crate](https://crates.io/crates/chrono). //! - `chrono-tz`: Integrate with the [`chrono-tz` crate](https://crates.io/crates/chrono-tz). //! - `url`: Integrate with the [`url` crate](https://crates.io/crates/url). //! - `uuid`: Integrate with the [`uuid` crate](https://crates.io/crates/uuid). //! - `string_number`: Enable the [StringNumber](extensions/types.StringNumber.html). //! //! ## Integrations //! //! * Actix-web [async-graphql-actix_web](https://crates.io/crates/async-graphql-actix-web) //! * Warp [async-graphql-warp](https://crates.io/crates/async-graphql-warp) //! * Tide [async-graphql-tide](https://crates.io/crates/async-graphql-tide) //! //! ## License //! //! Licensed under either of //! //! * Apache License, Version 2.0, //! (./LICENSE-APACHE or ) //! * MIT license (./LICENSE-MIT or ) //! at your option. //! //! ## References //! //! * [GraphQL](https://graphql.org) //! * [GraphQL Multipart Request](https://github.com/jaydenseric/graphql-multipart-request-spec) //! * [GraphQL Cursor Connections Specification](https://facebook.github.io/relay/graphql/connections.htm) //! * [GraphQL over WebSocket Protocol](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md) //! * [Apollo Tracing](https://github.com/apollographql/apollo-tracing) //! * [Apollo Federation](https://www.apollographql.com/docs/apollo-server/federation/introduction) //! //! ## Examples //! //! All examples are in the [sub-repository](https://github.com/async-graphql/examples), located in the examples directory. //! //! **Run an example:** //! //! ```shell //! git submodule update # update the examples repo //! cd examples && cargo run --bin [name] //! ``` //! //! ## Benchmarks //! //! Ensure that there is no CPU-heavy process in background! //! //! ```shell script //! cd benchmark //! cargo bench //! ``` //! //! Now a HTML report is available at `benchmark/target/criterion/report`. //! #![deny(clippy::all)] // #![deny(clippy::pedantic)] #![deny(clippy::inefficient_to_string)] #![deny(clippy::match_wildcard_for_single_variants)] #![allow(clippy::module_name_repetitions)] #![allow(clippy::similar_names)] #![allow(clippy::if_not_else)] #![allow(clippy::doc_markdown)] #![allow(clippy::must_use_candidate)] #![allow(clippy::missing_errors_doc)] #![allow(clippy::needless_pass_by_value)] #![deny(clippy::redundant_closure_for_method_calls)] #![allow(clippy::option_if_let_else)] #![allow(clippy::match_same_arms)] #![allow(clippy::filter_map)] #![allow(clippy::default_trait_access)] #![allow(clippy::map_flatten)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::explicit_iter_loop)] #![allow(clippy::too_many_lines)] #![allow(clippy::cast_sign_loss)] #![allow(clippy::unused_self)] #![allow(clippy::find_map)] #![allow(clippy::cast_lossless)] #![allow(clippy::cast_possible_truncation)] #![allow(clippy::implicit_hasher)] // #![deny(clippy::nursery)] #![allow(clippy::use_self)] #![allow(clippy::missing_const_for_fn)] #![allow(clippy::needless_borrow)] #![allow(clippy::future_not_send)] #![allow(clippy::redundant_pub_crate)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::useless_let_if_seq)] #![warn(missing_docs)] #![allow(clippy::trivially_copy_pass_by_ref)] #![recursion_limit = "256"] #![forbid(unsafe_code)] #![cfg_attr(feature = "nightly", feature(doc_cfg))] mod base; mod error; mod look_ahead; mod model; mod request; mod response; mod schema; mod subscription; mod validation; pub mod context; pub mod extensions; pub mod guard; pub mod http; pub mod resolver_utils; pub mod types; pub mod validators; #[doc(hidden)] pub mod registry; #[doc(hidden)] pub use async_stream; #[doc(hidden)] pub use async_trait; #[doc(hidden)] pub use context::ContextSelectionSet; #[doc(hidden)] pub use futures_util; #[doc(hidden)] pub use indexmap; #[doc(hidden)] pub use static_assertions; #[doc(hidden)] pub use subscription::SubscriptionType; pub use async_graphql_parser as parser; pub use async_graphql_value::{ from_value, to_value, value, ConstValue as Value, DeserializerError, Name, Number, SerializerError, }; pub use base::{ Description, InputObjectType, InputType, InterfaceType, ObjectType, OutputType, Type, UnionType, }; pub use error::{ Error, ErrorExtensionValues, ErrorExtensions, InputValueError, InputValueResult, ParseRequestError, PathSegment, Result, ResultExt, ServerError, ServerResult, }; pub use look_ahead::Lookahead; pub use registry::CacheControl; pub use request::{BatchRequest, Request}; #[doc(no_inline)] pub use resolver_utils::{ContainerType, EnumType, ScalarType}; pub use response::{BatchResponse, Response}; pub use schema::{Schema, SchemaBuilder, SchemaEnv}; pub use validation::ValidationMode; pub use context::*; #[doc(no_inline)] pub use parser::{Pos, Positioned}; pub use types::*; /// An alias of [async_graphql::Error](struct.Error.html). Present for backward compatibility /// reasons. pub type FieldError = Error; /// An alias of [async_graphql::Result](type.Result.html). Present for backward compatibility /// reasons. pub type FieldResult = Result; /// Define a GraphQL object with methods /// /// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_complex_object.html).* /// /// All methods are converted to camelCase. /// /// # Macro parameters /// /// | Attribute | description | Type | Optional | /// |---------------|---------------------------|----------|----------| /// | name | Object name | string | Y | /// | rename_fields | Rename all the fields according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y | /// | rename_args | Rename all the arguments according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y | /// | cache_control | Object cache control | [`CacheControl`](struct.CacheControl.html) | Y | /// | extends | Add fields to an entity that's defined in another service | bool | Y | /// | use_type_description | Specifies that the description of the type is on the type declaration. [`Description`]()(derive.Description.html) | bool | Y | /// /// # Field parameters /// /// | Attribute | description | Type | Optional | /// |---------------|---------------------------|----------|----------| /// | skip | Skip this field | bool | Y | /// | name | Field name | string | Y | /// | desc | Field description | string | Y | /// | deprecation | Field deprecation reason | string | Y | /// | cache_control | Field cache control | [`CacheControl`](struct.CacheControl.html) | Y | /// | external | Mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. | bool | Y | /// | provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y | /// | requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y | /// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y | /// /// # Field argument parameters /// /// | Attribute | description | Type | Optional | /// |--------------|------------------------------------------|------------ |----------| /// | name | Argument name | string | Y | /// | desc | Argument description | string | Y | /// | default | Use `Default::default` for default value | none | Y | /// | default | Argument default value | literal | Y | /// | default_with | Expression to generate default value | code string | Y | /// | validator | Input value validator | [`InputValueValidator`](validators/trait.InputValueValidator.html) | Y | /// | key | Is entity key | bool | Y | /// /// # Valid field return types /// /// - Scalar values, such as `i32` and `bool`. `usize`, `isize`, `u128` and `i128` are not /// supported /// - `Vec`, such as `Vec` /// - Slices, such as `&[i32]` /// - `Option`, such as `Option` /// - `BTree`, `HashMap`, `HashSet`, `BTreeSet`, `LinkedList`, `VecDeque` /// - GraphQL objects. /// - GraphQL enums. /// - References to any of the above types, such as `&i32` or `&Option`. /// - `Result`, such as `Result` /// /// # Context /// /// You can define a context as an argument to a method, and the context should be the first argument to the method. /// /// ```ignore /// #[Object] /// impl QueryRoot { /// async fn value(&self, ctx: &Context<'_>) -> { ... } /// } /// ``` /// /// # Examples /// /// ```rust /// use async_graphql::*; /// /// struct QueryRoot { /// value: i32, /// } /// /// #[Object] /// impl QueryRoot { /// /// value /// async fn value(&self) -> i32 { /// self.value /// } /// /// /// reference value /// async fn value_ref(&self) -> &i32 { /// &self.value /// } /// /// /// value with error /// async fn value_with_error(&self) -> Result { /// Ok(self.value) /// } /// /// async fn value_with_arg(&self, #[graphql(default = 1)] a: i32) -> i32 { /// a /// } /// } /// /// async_std::task::block_on(async move { /// let schema = Schema::new(QueryRoot { value: 10 }, EmptyMutation, EmptySubscription); /// let res = schema.execute(r#"{ /// value /// valueRef /// valueWithError /// valueWithArg1: valueWithArg /// valueWithArg2: valueWithArg(a: 99) /// }"#).await.into_result().unwrap().data; /// assert_eq!(res, value!({ /// "value": 10, /// "valueRef": 10, /// "valueWithError": 10, /// "valueWithArg1": 1, /// "valueWithArg2": 99 /// })); /// }); /// ``` pub use async_graphql_derive::Object; /// Define a GraphQL object with fields /// /// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_simple_object.html).* /// /// Similar to `Object`, but defined on a structure that automatically generates getters for all fields. For a list of valid field types, see [`Object`](attr.Object.html). All fields are converted to camelCase. /// /// # Macro parameters /// /// | Attribute | description | Type | Optional | /// |---------------|---------------------------|----------|----------| /// | name | Object name | string | Y | /// | rename_fields | Rename all the fields according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y | /// | cache_control | Object cache control | [`CacheControl`](struct.CacheControl.html) | Y | /// | extends | Add fields to an entity that's defined in another service | bool | Y | /// /// # Field parameters /// /// | Attribute | description | Type | Optional | /// |---------------|---------------------------|----------|----------| /// | skip | Skip this field | bool | Y | /// | name | Field name | string | Y | /// | deprecation | Field deprecation reason | string | Y | /// | owned | Field resolver return a ownedship value | bool | Y | /// | cache_control | Field cache control | [`CacheControl`](struct.CacheControl.html) | Y | /// | external | Mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. | bool | Y | /// | provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y | /// | requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y | /// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y | /// /// # Examples /// /// ```rust /// use async_graphql::*; /// /// #[derive(SimpleObject)] /// struct QueryRoot { /// value: i32, /// } /// /// async_std::task::block_on(async move { /// let schema = Schema::new(QueryRoot{ value: 10 }, EmptyMutation, EmptySubscription); /// let res = schema.execute("{ value }").await.into_result().unwrap().data; /// assert_eq!(res, value!({ /// "value": 10, /// })); /// }); /// ``` pub use async_graphql_derive::SimpleObject; /// Define a GraphQL enum /// /// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_enum.html).* /// /// # Macro parameters /// /// | Attribute | description | Type | Optional | /// |--------------|---------------------------|----------|----------| /// | name | Enum name | string | Y | /// | rename_items | Rename all the fields according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y | /// | remote | Derive a remote enum | string | Y | /// /// # Item parameters /// /// | Attribute | description | Type | Optional | /// |-------------|---------------------------|----------|----------| /// | name | Item name | string | Y | /// | deprecation | Item deprecation reason | string | Y | /// /// # Examples /// /// ```rust /// use async_graphql::*; /// /// #[derive(Enum, Copy, Clone, Eq, PartialEq)] /// enum MyEnum { /// A, /// #[graphql(name = "b")] B, /// } /// /// struct QueryRoot { /// value1: MyEnum, /// value2: MyEnum, /// } /// /// #[Object] /// impl QueryRoot { /// /// value1 /// async fn value1(&self) -> MyEnum { /// self.value1 /// } /// /// /// value2 /// async fn value2(&self) -> MyEnum { /// self.value2 /// } /// } /// /// async_std::task::block_on(async move { /// let schema = Schema::new(QueryRoot{ value1: MyEnum::A, value2: MyEnum::B }, EmptyMutation, EmptySubscription); /// let res = schema.execute("{ value1 value2 }").await.into_result().unwrap().data; /// assert_eq!(res, value!({ "value1": "A", "value2": "b" })); /// }); /// ``` pub use async_graphql_derive::Enum; /// Define a GraphQL input object /// /// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_input_object.html).* /// /// # Macro parameters /// /// | Attribute | description | Type | Optional | /// |---------------|---------------------------|----------|----------| /// | name | Object name | string | Y | /// | rename_fields | Rename all the fields according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y | /// /// # Field parameters /// /// | Attribute | description | Type | Optional | /// |--------------|------------------------------------------|-------------|----------| /// | name | Field name | string | Y | /// | default | Use `Default::default` for default value | none | Y | /// | default | Argument default value | literal | Y | /// | default_with | Expression to generate default value | code string | Y | /// | validator | Input value validator | [`InputValueValidator`](validators/trait.InputValueValidator.html) | Y | /// | flatten | Similar to serde (flatten) | boolean | Y | /// /// # Examples /// /// ```rust /// use async_graphql::*; /// /// #[derive(InputObject)] /// struct MyInputObject { /// a: i32, /// #[graphql(default = 10)] /// b: i32, /// } /// /// struct QueryRoot; /// /// #[Object] /// impl QueryRoot { /// /// value /// async fn value(&self, input: MyInputObject) -> i32 { /// input.a * input.b /// } /// } /// /// async_std::task::block_on(async move { /// let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription); /// let res = schema.execute(r#" /// { /// value1: value(input:{a:9, b:3}) /// value2: value(input:{a:9}) /// }"#).await.into_result().unwrap().data; /// assert_eq!(res, value!({ "value1": 27, "value2": 90 })); /// }); /// ``` pub use async_graphql_derive::InputObject; /// Define a GraphQL interface /// /// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_interface.html).* /// /// # Macro parameters /// /// | Attribute | description | Type | Optional | /// |---------------|---------------------------|----------|----------| /// | name | Object name | string | Y | /// | rename_fields | Rename all the fields according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y | /// | rename_args | Rename all the arguments according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y | /// | field | Fields of this Interface | [InterfaceField] | N | /// | extends | Add fields to an entity that's defined in another service | bool | Y | /// /// # Field parameters /// /// | Attribute | description | Type | Optional | /// |-------------|---------------------------|----------|----------| /// | name | Field name | string | N | /// | type | Field type | string | N | /// | method | Rust resolver method name. If specified, `name` will not be camelCased in schema definition | string | Y | /// | desc | Field description | string | Y | /// | deprecation | Field deprecation reason | string | Y | /// | arg | Field arguments | [InterfaceFieldArgument] | Y | /// | external | Mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. | bool | Y | /// | provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y | /// | requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y | /// /// # Field argument parameters /// /// | Attribute | description | Type | Optional | /// |--------------|------------------------------------------|-------------|----------| /// | name | Argument name | string | N | /// | type | Argument type | string | N | /// | desc | Argument description | string | Y | /// | default | Use `Default::default` for default value | none | Y | /// | default | Argument default value | literal | Y | /// | default_with | Expression to generate default value | code string | Y | /// /// # Define an interface /// /// Define TypeA, TypeB, TypeC... Implement the MyInterface /// /// ```ignore /// #[derive(Interface)] /// enum MyInterface { /// TypeA(TypeA), /// TypeB(TypeB), /// TypeC(TypeC), /// ... /// } /// ``` /// /// # Fields /// /// The type, name, and parameter fields of the interface must exactly match the type of the /// implementation interface, but Result can be omitted. /// /// ```rust /// use async_graphql::*; /// /// struct TypeA { /// value: i32, /// } /// /// #[Object] /// impl TypeA { /// /// Returns data borrowed from the context /// async fn value_a<'a>(&self, ctx: &'a Context<'_>) -> Result<&'a str> { /// Ok(ctx.data::()?.as_str()) /// } /// /// /// Returns data borrowed self /// async fn value_b(&self) -> &i32 { /// &self.value /// } /// /// /// With parameters /// async fn value_c(&self, a: i32, b: i32) -> i32 { /// a + b /// } /// /// /// Disabled name transformation, don't forget "method" argument in interface! /// #[graphql(name = "value_d")] /// async fn value_d(&self) -> i32 { /// &self.value + 1 /// } /// } /// /// #[derive(Interface)] /// #[graphql( /// field(name = "value_a", type = "&'ctx str"), /// field(name = "value_b", type = "&i32"), /// field(name = "value_c", type = "i32", /// arg(name = "a", type = "i32"), /// arg(name = "b", type = "i32")), /// field(name = "value_d", method = "value_d", type = "i32"), /// )] /// enum MyInterface { /// TypeA(TypeA) /// } /// /// struct QueryRoot; /// /// #[Object] /// impl QueryRoot { /// async fn type_a(&self) -> MyInterface { /// TypeA { value: 10 }.into() /// } /// } /// /// async_std::task::block_on(async move { /// let schema = Schema::build(QueryRoot, 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 /// } /// })); /// }); /// ``` pub use async_graphql_derive::Interface; /// Define a GraphQL union /// /// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_union.html).* /// /// # Macro parameters /// /// | Attribute | description | Type | Optional | /// |-------------|---------------------------|----------|----------| /// | name | Object name | string | Y | /// /// # Item parameters /// /// | Attribute | description | Type | Optional | /// |--------------|------------------------------------------|----------|----------| /// | flatten | Similar to serde (flatten) | boolean | Y | /// /// # Define a union /// /// Define TypeA, TypeB, ... as MyUnion /// /// ```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 QueryRoot; /// /// #[Object] /// impl QueryRoot { /// async fn all_data(&self) -> Vec { /// vec![TypeA { value_a: 10 }.into(), TypeB { value_b: 20 }.into()] /// } /// } /// /// async_std::task::block_on(async move { /// let schema = Schema::build(QueryRoot, 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 }, /// ] /// })); /// }); /// ``` pub use async_graphql_derive::Union; /// Define a GraphQL subscription /// /// *[See also the Book](https://async-graphql.github.io/async-graphql/en/subscription.html).* /// /// The field function is a synchronization function that performs filtering. When true is returned, the message is pushed to the client. /// The second parameter is the type of the field. /// Starting with the third parameter is one or more filtering conditions, The filter condition is the parameter of the field. /// The filter function should be synchronous. /// /// # Macro parameters /// /// | Attribute | description | Type | Optional | /// |---------------|---------------------------|----------|----------| /// | name | Object name | string | Y | /// | rename_fields | Rename all the fields according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y | /// | rename_args | Rename all the arguments according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y | /// | use_type_description | Specifies that the description of the type is on the type declaration. [`Description`]()(derive.Description.html) | bool | Y | /// /// # Field parameters /// /// | Attribute | description | Type | Optional | /// |-------------|---------------------------|----------|----------| /// | name | Field name | string | Y | /// | deprecation | Field deprecation reason | string | Y | /// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y | /// /// # Field argument parameters /// /// | Attribute | description | Type | Optional | /// |--------------|------------------------------------------|------------ |----------| /// | name | Argument name | string | Y | /// | desc | Argument description | string | Y | /// | default | Use `Default::default` for default value | none | Y | /// | default | Argument default value | literal | Y | /// | default_with | Expression to generate default value | code string | Y | /// | validator | Input value validator | [`InputValueValidator`](validators/trait.InputValueValidator.html) | Y | /// /// # Examples /// /// ```rust /// use async_graphql::*; /// use futures_util::stream::{Stream, StreamExt}; /// /// struct SubscriptionRoot; /// /// #[Subscription] /// impl SubscriptionRoot { /// async fn value(&self, condition: i32) -> impl Stream { /// // Returns the number from 0 to `condition`. /// futures_util::stream::iter(0..condition) /// } /// } /// ``` pub use async_graphql_derive::Subscription; /// Define a Scalar /// /// # Macro parameters /// /// | Attribute | description | Type | Optional | /// |-------------|---------------------------|----------|----------| /// | name | Scalar name | string | Y | /// pub use async_graphql_derive::Scalar; /// Define a merged object with multiple object types. /// /// *[See also the Book](https://async-graphql.github.io/async-graphql/en/merging_objects.html).* /// /// # Macro parameters /// /// | Attribute | description | Type | Optional | /// |---------------|---------------------------|----------|----------| /// | name | Object name | string | Y | /// | cache_control | Object cache control | [`CacheControl`](struct.CacheControl.html) | Y | /// | extends | Add fields to an entity that's defined in another service | bool | Y | /// | use_type_description | Specifies that the description of the type is on the type declaration. [`Description`]()(derive.Description.html) | bool | Y | /// /// # Examples /// /// ```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 MyObj(Object1, Object2, Object3); /// /// let obj = MyObj(Object1 { a: 10 }, Object2 { b: 20 }, Object3 { c: 30 }); /// ``` pub use async_graphql_derive::MergedObject; /// Define a merged subscription with multiple subscription types. /// /// *[See also the Book](https://async-graphql.github.io/async-graphql/en/merging_objects.html).* /// /// # Macro parameters /// /// | Attribute | description | Type | Optional | /// |---------------|---------------------------|----------|----------| /// | name | Object name | string | Y | /// /// # Examples /// /// ```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); /// ``` pub use async_graphql_derive::MergedSubscription; /// Attach a description to `Object`, `Scalar` or `Subscription`. /// /// The three types above use the rustdoc on the implementation block as /// the GraphQL type description, but if you want to use the rustdoc on the /// type declaration as the GraphQL type description, you can use that derived macro. /// /// # Examples /// /// ```rust /// use async_graphql::*; /// /// /// This is MyObj /// #[derive(Description, Default)] /// struct MyObj; /// /// #[Object(use_type_description)] /// impl MyObj { /// async fn value(&self) -> i32 { /// 100 /// } /// } /// /// #[derive(SimpleObject, Default)] /// struct Query { /// obj: MyObj, /// } /// /// async_std::task::block_on(async move { /// let schema = Schema::new(Query::default(), EmptyMutation, EmptySubscription); /// assert_eq!( /// schema /// .execute(r#"{ __type(name: "MyObj") { description } }"#) /// .await /// .data, /// value!({ /// "__type": { "description": "This is MyObj" } /// }) /// ); /// }); /// ``` pub use async_graphql_derive::Description;