async-graphql/src/lib.rs

796 lines
28 KiB
Rust
Raw Normal View History

2020-05-25 21:37:46 +00:00
//! # A GraphQL server library implemented in Rust
2020-03-01 13:56:14 +00:00
//!
//! <div align="center">
//! <!-- CI -->
2020-04-28 07:41:31 +00:00
//! <img src="https://github.com/async-graphql/async-graphql/workflows/CI/badge.svg" />
2020-04-05 08:22:13 +00:00
//! <!-- codecov -->
2020-04-28 07:41:31 +00:00
// <img src="https://codecov.io/gh/async-graphql/async-graphql/branch/master/graph/badge.svg" />
2020-03-01 13:56:14 +00:00
//! <!-- Crates version -->
//! <a href="https://crates.io/crates/async-graphql">
//! <img src="https://img.shields.io/crates/v/async-graphql.svg?style=flat-square"
//! alt="Crates.io version" />
//! </a>
//! <!-- Downloads -->
//! <a href="https://crates.io/crates/async-graphql">
//! <img src="https://img.shields.io/crates/d/async-graphql.svg?style=flat-square"
//! alt="Download" />
//! </a>
//! <!-- docs.rs docs -->
//! <a href="https://docs.rs/async-graphql">
//! <img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square"
//! alt="docs.rs docs" />
//! </a>
//! </div>
//!
//! ## Documentation
//!
2020-05-10 01:41:13 +00:00
//! * [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)
2020-04-28 07:41:31 +00:00
//! * [GitHub repository](https://github.com/async-graphql/async-graphql)
2020-03-01 13:56:14 +00:00
//! * [Cargo package](https://crates.io/crates/async-graphql)
//! * Minimum supported Rust version: 1.42 or later
2020-03-01 13:56:14 +00:00
//!
2020-03-04 06:27:00 +00:00
//! ## Features
//!
2020-07-07 08:41:29 +00:00
//! * Fully supports async/await
2020-03-17 11:11:14 +00:00
//! * Type safety
//! * Rustfmt friendly (Procedural Macro)
2020-07-07 08:41:29 +00:00
//! * Custom scalars
2020-03-17 11:11:14 +00:00
//! * Minimal overhead
2020-09-14 06:13:43 +00:00
//! * Easy integration (actix_web, tide, warp, rocket ...)
//! * File upload (Multipart request)
2020-07-07 08:41:29 +00:00
//! * Subscriptions (WebSocket transport)
//! * Custom extensions
2020-03-26 03:34:28 +00:00
//! * Apollo Tracing extension
//! * Limit query complexity/depth
2020-03-31 03:19:18 +00:00
//! * Error Extensions
2020-04-10 02:26:08 +00:00
//! * Apollo Federation
2020-09-17 08:39:55 +00:00
//! * Batch Queries
2020-03-04 06:27:00 +00:00
//!
2020-03-18 03:15:02 +00:00
//! ## Integrations
//!
//! * Actix-web [async-graphql-actix_web](https://crates.io/crates/async-graphql-actix-web)
2020-04-14 03:44:49 +00:00
//! * Warp [async-graphql-warp](https://crates.io/crates/async-graphql-warp)
2020-05-02 02:46:02 +00:00
//! * Tide [async-graphql-tide](https://crates.io/crates/async-graphql-tide)
2020-03-18 03:15:02 +00:00
//!
2020-03-04 06:27:00 +00:00
//! ## License
//!
//! Licensed under either of
//!
//! * Apache License, Version 2.0,
2020-09-15 18:32:13 +00:00
//! (./LICENSE-APACHE or <http://www.apache.org/licenses/LICENSE-2.0>)
//! * MIT license (./LICENSE-MIT or <http://opensource.org/licenses/MIT>)
2020-03-04 06:27:00 +00:00
//! at your option.
//!
2020-03-01 13:56:14 +00:00
//! ## References
//!
//! * [GraphQL](https://graphql.org)
2020-03-20 03:56:08 +00:00
//! * [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)
2020-03-26 07:27:35 +00:00
//! * [Apollo Tracing](https://github.com/apollographql/apollo-tracing)
2020-04-10 02:28:27 +00:00
//! * [Apollo Federation](https://www.apollographql.com/docs/apollo-server/federation/introduction)
//!
//! ## Examples
//!
//! If you are just getting started, we recommend checking out our examples at:
//! [https://github.com/async-graphql/examples](https://github.com/async-graphql/examples)
//!
//! To see how you would create a Relay-compliant server using async-graphql, warp, diesel & postgresql, you can also check out a real-world example at:
//! [https://github.com/phated/twentyfive-stars](https://github.com/phated/twentyfive-stars)
//!
//! ## Benchmarks
//!
2020-06-02 00:57:45 +00:00
//! Ensure that there is no CPU-heavy process in background!
//!
//! ```shell script
2020-06-02 00:57:45 +00:00
//! cd benchmark
//! cargo bench
//! ```
//!
//! Now a HTML report is available at `benchmark/target/criterion/report`.
2020-06-02 00:57:45 +00:00
//!
2020-09-15 18:32:13 +00:00
//! # 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).
//! - `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).
2020-09-18 07:05:07 +00:00
//! - `unblock`: Support [asynchronous reader for Upload](types/struct.Upload.html)
2020-09-15 18:32:13 +00:00
//! - `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).
2020-03-20 03:56:08 +00:00
#![warn(missing_docs)]
#![allow(clippy::trivially_copy_pass_by_ref)]
2020-05-20 00:18:28 +00:00
#![recursion_limit = "256"]
2020-05-29 09:29:15 +00:00
#![forbid(unsafe_code)]
2020-09-15 18:32:13 +00:00
#![cfg_attr(feature = "nightly", feature(doc_cfg))]
2020-03-01 13:56:14 +00:00
2020-03-03 03:48:00 +00:00
mod base;
2020-03-01 10:54:34 +00:00
mod context;
mod error;
2020-05-14 14:13:28 +00:00
mod look_ahead;
2020-03-03 11:15:18 +00:00
mod model;
2020-09-10 08:39:43 +00:00
mod request;
mod response;
2020-03-03 11:15:18 +00:00
mod schema;
2020-09-10 04:49:08 +00:00
mod serialize_resp;
2020-03-17 09:26:59 +00:00
mod subscription;
2020-03-08 12:35:36 +00:00
mod validation;
2020-03-01 10:54:34 +00:00
pub mod extensions;
2020-05-01 23:57:34 +00:00
pub mod guard;
2020-09-19 05:14:59 +00:00
pub mod http;
2020-09-13 09:38:19 +00:00
pub mod types;
2020-09-14 01:46:22 +00:00
pub mod validators;
2020-03-21 01:32:13 +00:00
#[doc(hidden)]
2020-09-19 05:14:59 +00:00
pub mod registry;
#[doc(hidden)]
2020-09-19 05:14:59 +00:00
pub mod resolver_utils;
2020-03-01 17:15:05 +00:00
#[doc(hidden)]
pub use async_stream;
#[doc(hidden)]
2020-09-14 01:46:22 +00:00
pub use async_trait;
#[doc(hidden)]
pub use context::ContextSelectionSet;
#[doc(hidden)]
pub use futures;
#[doc(hidden)]
pub use indexmap;
#[doc(hidden)]
2020-03-01 10:54:34 +00:00
pub use serde_json;
2020-09-19 05:14:59 +00:00
#[doc(hidden)]
pub use subscription::SubscriptionType;
2020-03-01 10:54:34 +00:00
2020-09-19 05:14:59 +00:00
pub use async_graphql_parser as parser;
pub use base::{InputValueType, OutputValueType, ScalarType, Type};
pub use context::{
Context, ContextBase, Data, QueryEnv, QueryPathNode, QueryPathSegment, Variables,
};
2020-04-14 01:53:17 +00:00
pub use error::{
Error, ErrorExtensions, FieldError, FieldResult, InputValueError, InputValueResult,
ParseRequestError, QueryError, ResultExt, RuleError,
2020-04-14 01:53:17 +00:00
};
2020-05-14 14:13:28 +00:00
pub use look_ahead::Lookahead;
2020-09-19 05:14:59 +00:00
pub use parser::types::{ConstValue as Value, Number};
2020-03-22 08:45:59 +00:00
pub use registry::CacheControl;
2020-09-17 08:39:55 +00:00
pub use request::{BatchRequest, Request};
pub use response::{BatchResponse, Response};
pub use schema::{Schema, SchemaBuilder, SchemaEnv};
2020-09-14 01:46:22 +00:00
pub use validation::ValidationMode;
2020-03-02 00:24:49 +00:00
2020-09-19 05:14:59 +00:00
#[doc(no_inline)]
pub use parser::{Pos, Positioned};
pub use types::*;
/// Result type
pub type Result<T> = std::result::Result<T, Error>;
2020-03-01 13:35:39 +00:00
// internal types
2020-03-09 10:05:52 +00:00
/// 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.
2020-03-09 10:05:52 +00:00
///
/// # Macro parameters
///
2020-03-22 08:45:59 +00:00
/// | Attribute | description | Type | Optional |
/// |---------------|---------------------------|----------|----------|
/// | name | Object name | string | Y |
/// | desc | Object description | string | Y |
/// | cache_control | Object cache control | [`CacheControl`](struct.CacheControl.html) | Y |
2020-04-09 14:03:09 +00:00
/// | extends | Add fields to an entity that's defined in another service | bool | Y |
2020-03-09 10:05:52 +00:00
///
/// # Field parameters
///
2020-03-22 08:45:59 +00:00
/// | Attribute | description | Type | Optional |
/// |---------------|---------------------------|----------|----------|
/// | 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 |
2020-04-09 14:03:09 +00:00
/// | 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 |
2020-05-01 23:57:34 +00:00
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
/// | feature | It's like a `#[cfg(feature = "foo")]` attribute but instead of not compiling this field it will just return a proper `FieldError` to tell you this feature is not enabled | string ("feature1,feature2") | Y |
2020-03-09 10:05:52 +00:00
///
/// # Field argument parameters
///
2020-07-07 08:41:29 +00:00
/// | 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 |
2020-03-09 10:05:52 +00:00
///
/// # Valid field return types
2020-03-09 10:05:52 +00:00
///
/// - Scalar values, such as `i32` and `bool`. `usize`, `isize`, `u128` and `i128` are not
/// supported
/// - `Vec<T>`, such as `Vec<i32>`
/// - Slices, such as `&[i32]`
/// - `Option<T>`, such as `Option<i32>`
/// - GraphQL objects.
/// - GraphQL enums.
/// - References to any of the above types, such as `&i32` or `&Option<String>`.
/// - `FieldResult<T, E>`, such as `FieldResult<i32, E>`
2020-03-09 10:05:52 +00:00
///
/// # 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]
2020-03-27 02:20:20 +00:00
/// impl QueryRoot {
2020-03-09 10:05:52 +00:00
/// async fn value(&self, ctx: &Context<'_>) -> { ... }
/// }
/// ```
///
/// # Examples
///
/// ```rust
/// use async_graphql::*;
///
2020-03-27 02:20:20 +00:00
/// struct QueryRoot {
2020-03-09 10:05:52 +00:00
/// value: i32,
/// }
///
/// #[Object]
2020-03-27 02:20:20 +00:00
/// impl QueryRoot {
2020-03-09 10:05:52 +00:00
/// #[field(desc = "value")]
/// async fn value(&self) -> i32 {
/// self.value
/// }
///
2020-03-10 06:14:09 +00:00
/// #[field(desc = "reference value")]
2020-03-09 10:05:52 +00:00
/// async fn value_ref(&self) -> &i32 {
/// &self.value
/// }
///
2020-03-10 06:14:09 +00:00
/// #[field(desc = "value with error")]
/// async fn value_with_error(&self) -> FieldResult<i32> {
2020-03-09 10:05:52 +00:00
/// Ok(self.value)
/// }
///
/// async fn value_with_arg(&self, #[arg(default = 1)] a: i32) -> i32 {
2020-03-09 10:05:52 +00:00
/// a
/// }
/// }
///
2020-08-10 06:57:45 +00:00
/// async_std::task::block_on(async move {
/// let schema = Schema::new(QueryRoot { value: 10 }, EmptyMutation, EmptySubscription);
2020-04-02 04:53:53 +00:00
/// let res = schema.execute(r#"{
2020-03-09 10:05:52 +00:00
/// value
/// valueRef
/// valueWithError
/// valueWithArg1: valueWithArg
/// valueWithArg2: valueWithArg(a: 99)
/// }"#).await.into_result().unwrap().data;
2020-03-09 10:05:52 +00:00
/// assert_eq!(res, serde_json::json!({
/// "value": 10,
/// "valueRef": 10,
/// "valueWithError": 10,
/// "valueWithArg1": 1,
/// "valueWithArg2": 99
/// }));
2020-08-10 06:57:45 +00:00
/// });
2020-03-09 10:05:52 +00:00
/// ```
pub use async_graphql_derive::Object;
2020-03-09 10:05:52 +00:00
/// 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.
2020-03-27 02:20:20 +00:00
///
/// # Macro parameters
///
/// | Attribute | description | Type | Optional |
/// |---------------|---------------------------|----------|----------|
/// | name | Object name | string | Y |
/// | desc | Object description | string | Y |
/// | cache_control | Object cache control | [`CacheControl`](struct.CacheControl.html) | Y |
///
/// # Field parameters
///
/// | Attribute | description | Type | Optional |
/// |---------------|---------------------------|----------|----------|
/// | name | Field name | string | Y |
/// | desc | Field description | string | Y |
/// | deprecation | Field deprecation reason | string | Y |
/// | owned | Field resolver return a ownedship value | bool | Y |
2020-03-27 02:20:20 +00:00
/// | cache_control | Field cache control | [`CacheControl`](struct.CacheControl.html) | Y |
2020-04-26 02:12:01 +00:00
/// | 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 |
2020-05-01 23:57:34 +00:00
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
/// | feature | It's like a `#[cfg(feature = "foo")]` attribute but instead of not compiling this field it will just return a proper `FieldError` to tell you this feature is not enabled | string ("feature1,feature2") | Y |
2020-03-27 02:20:20 +00:00
///
/// # Examples
///
/// ```rust
/// use async_graphql::*;
///
/// #[derive(SimpleObject)]
2020-03-27 02:20:20 +00:00
/// struct QueryRoot {
/// value: i32,
/// }
///
2020-08-10 06:57:45 +00:00
/// async_std::task::block_on(async move {
2020-03-27 02:20:20 +00:00
/// let schema = Schema::new(QueryRoot{ value: 10 }, EmptyMutation, EmptySubscription);
/// let res = schema.execute("{ value }").await.into_result().unwrap().data;
2020-03-27 02:20:20 +00:00
/// assert_eq!(res, serde_json::json!({
/// "value": 10,
/// }));
2020-08-10 06:57:45 +00:00
/// });
2020-03-27 02:20:20 +00:00
/// ```
pub use async_graphql_derive::SimpleObject;
2020-03-09 10:05:52 +00:00
/// Define a GraphQL enum
///
/// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_enum.html).*
///
2020-03-09 10:05:52 +00:00
/// # Macro parameters
///
/// | Attribute | description | Type | Optional |
/// |-------------|---------------------------|----------|----------|
/// | name | Enum name | string | Y |
/// | desc | Enum description | string | Y |
///
/// # Item parameters
///
/// | Attribute | description | Type | Optional |
/// |-------------|---------------------------|----------|----------|
/// | name | Item name | string | Y |
/// | desc | Item description | string | Y |
/// | deprecation | Item deprecation reason | string | Y |
///
/// # Examples
///
/// ```rust
/// use async_graphql::*;
///
/// #[derive(Enum, Copy, Clone, Eq, PartialEq)]
2020-03-09 10:05:52 +00:00
/// enum MyEnum {
/// A,
/// #[item(name = "b")] B,
/// }
///
2020-03-27 02:20:20 +00:00
/// struct QueryRoot {
2020-03-09 10:05:52 +00:00
/// value1: MyEnum,
/// value2: MyEnum,
/// }
///
/// #[Object]
2020-03-27 02:20:20 +00:00
/// impl QueryRoot {
2020-03-09 10:05:52 +00:00
/// #[field(desc = "value")]
/// async fn value1(&self) -> MyEnum {
/// self.value1
/// }
///
/// #[field(desc = "value")]
/// async fn value2(&self) -> MyEnum {
/// self.value2
/// }
/// }
///
2020-08-10 06:57:45 +00:00
/// async_std::task::block_on(async move {
2020-03-27 02:20:20 +00:00
/// let schema = Schema::new(QueryRoot{ value1: MyEnum::A, value2: MyEnum::B }, EmptyMutation, EmptySubscription);
/// let res = schema.execute("{ value1 value2 }").await.into_result().unwrap().data;
2020-03-09 10:05:52 +00:00
/// assert_eq!(res, serde_json::json!({ "value1": "A", "value2": "b" }));
2020-08-10 06:57:45 +00:00
/// });
2020-03-09 10:05:52 +00:00
/// ```
pub use async_graphql_derive::Enum;
2020-03-09 10:05:52 +00:00
/// Define a GraphQL input object
///
/// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_input_object.html).*
///
2020-03-09 10:05:52 +00:00
/// # Macro parameters
///
/// | Attribute | description | Type | Optional |
/// |-------------|---------------------------|----------|----------|
/// | name | Object name | string | Y |
/// | desc | Object description | string | Y |
///
/// # Field parameters
///
2020-07-07 08:41:29 +00:00
/// | Attribute | description | Type | Optional |
/// |--------------|------------------------------------------|----------|----------|
/// | name | Field name | string | Y |
/// | desc | Field 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 |
2020-09-03 12:20:33 +00:00
/// | flatten | Similar to serde (flatten) | boolean | Y |
2020-03-09 10:05:52 +00:00
///
/// # Examples
///
/// ```rust
/// use async_graphql::*;
///
/// #[derive(InputObject)]
2020-03-09 10:05:52 +00:00
/// struct MyInputObject {
/// a: i32,
/// #[field(default = 10)]
2020-03-09 10:05:52 +00:00
/// b: i32,
/// }
///
2020-03-27 02:20:20 +00:00
/// struct QueryRoot;
2020-03-09 10:05:52 +00:00
///
/// #[Object]
2020-03-27 02:20:20 +00:00
/// impl QueryRoot {
2020-03-09 10:05:52 +00:00
/// #[field(desc = "value")]
/// async fn value(&self, input: MyInputObject) -> i32 {
/// input.a * input.b
/// }
/// }
///
2020-08-10 06:57:45 +00:00
/// async_std::task::block_on(async move {
2020-03-27 02:20:20 +00:00
/// let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
2020-04-02 04:53:53 +00:00
/// let res = schema.execute(r#"
2020-03-09 10:05:52 +00:00
/// {
/// value1: value(input:{a:9, b:3})
/// value2: value(input:{a:9})
/// }"#).await.into_result().unwrap().data;
2020-03-09 10:05:52 +00:00
/// assert_eq!(res, serde_json::json!({ "value1": 27, "value2": 90 }));
2020-08-10 06:57:45 +00:00
/// });
2020-03-09 10:05:52 +00:00
/// ```
pub use async_graphql_derive::InputObject;
2020-03-09 10:05:52 +00:00
/// Define a GraphQL interface
///
/// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_interface.html).*
///
2020-03-09 10:05:52 +00:00
/// # Macro parameters
///
/// | Attribute | description | Type | Optional |
/// |-------------|---------------------------|----------|----------|
/// | name | Object name | string | Y |
/// | desc | Object description | string | Y |
///
/// # Field parameters
///
/// | Attribute | description | Type | Optional |
/// |-------------|---------------------------|----------|----------|
/// | name | Field name | string | N |
/// | method | Rust resolver method name. If specified, `name` will not be camelCased in schema definition | string | Y |
2020-03-09 10:05:52 +00:00
/// | type | Field type | string | N |
/// | desc | Field description | string | Y |
/// | deprecation | Field deprecation reason | string | Y |
2020-03-22 01:34:32 +00:00
/// | args | Field arguments | | Y |
2020-03-09 10:05:52 +00:00
///
/// # Field argument parameters
///
2020-07-07 08:41:29 +00:00
/// | 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 |
2020-03-09 10:05:52 +00:00
///
/// # Define an interface
///
/// Define TypeA, TypeB, TypeC... Implement the MyInterface
///
/// ```ignore
/// #[derive(Interface)]
2020-05-11 03:25:49 +00:00
/// enum MyInterface {
/// TypeA(TypeA),
/// TypeB(TypeB),
/// TypeC(TypeC),
/// ...
/// }
2020-03-09 10:05:52 +00:00
/// ```
///
/// # Fields
///
2020-05-02 02:46:02 +00:00
/// The type, name, and parameter fields of the interface must exactly match the type of the
/// implementation interface, but FieldResult can be omitted.
2020-03-09 10:05:52 +00:00
///
/// ```rust
/// use async_graphql::*;
///
/// struct TypeA {
/// value: i32,
/// }
///
/// #[Object]
2020-03-09 10:05:52 +00:00
/// impl TypeA {
/// /// Returns data borrowed from the context
/// async fn value_a<'a>(&self, ctx: &'a Context<'_>) -> FieldResult<&'a str> {
/// Ok(ctx.data::<String>()?.as_str())
2020-03-09 10:05:52 +00:00
/// }
///
/// /// 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!
/// #[field(name = "value_d")]
/// async fn value_d(&self) -> i32 {
/// &self.value + 1
/// }
2020-03-09 10:05:52 +00:00
/// }
///
/// #[derive(Interface)]
/// #[graphql(
2020-05-01 23:57:34 +00:00
/// field(name = "value_a", type = "&'ctx str"),
2020-03-09 10:05:52 +00:00
/// 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"),
2020-03-09 10:05:52 +00:00
/// )]
2020-05-11 03:25:49 +00:00
/// enum MyInterface {
/// TypeA(TypeA)
/// }
2020-03-09 10:05:52 +00:00
///
/// struct QueryRoot;
///
/// #[Object]
2020-03-09 10:05:52 +00:00
/// impl QueryRoot {
/// async fn type_a(&self) -> MyInterface {
/// TypeA { value: 10 }.into()
/// }
/// }
///
2020-08-10 06:57:45 +00:00
/// async_std::task::block_on(async move {
2020-03-29 12:02:52 +00:00
/// let schema = Schema::build(QueryRoot, EmptyMutation, EmptySubscription).data("hello".to_string()).finish();
2020-04-02 04:53:53 +00:00
/// let res = schema.execute(r#"
2020-03-09 10:05:52 +00:00
/// {
2020-03-09 12:00:57 +00:00
/// typeA {
/// valueA
/// valueB
/// valueC(a: 3, b: 2)
/// value_d
2020-03-09 10:05:52 +00:00
/// }
/// }"#).await.into_result().unwrap().data;
2020-03-09 10:05:52 +00:00
/// assert_eq!(res, serde_json::json!({
2020-03-09 12:00:57 +00:00
/// "typeA": {
/// "valueA": "hello",
/// "valueB": 10,
/// "valueC": 5,
/// "value_d": 11
2020-03-09 10:05:52 +00:00
/// }
/// }));
2020-08-10 06:57:45 +00:00
/// });
2020-03-09 10:05:52 +00:00
/// ```
pub use async_graphql_derive::Interface;
2020-06-11 07:08:51 +00:00
2020-03-09 12:59:31 +00:00
/// Define a GraphQL union
2020-03-09 12:59:25 +00:00
///
/// *[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 |
/// | desc | Object description | string | 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<MyUnion> {
/// vec![TypeA { value_a: 10 }.into(), TypeB { value_b: 20 }.into()]
/// }
/// }
///
2020-08-10 06:57:45 +00:00
/// 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, serde_json::json!({
/// "allData": [
/// { "valueA": 10 },
/// { "valueB": 20 },
/// ]
/// }));
2020-08-10 06:57:45 +00:00
/// });
/// ```
pub use async_graphql_derive::Union;
2020-06-11 07:08:51 +00:00
2020-03-17 11:11:14 +00:00
/// Define a GraphQL subscription
///
/// *[See also the Book](https://async-graphql.github.io/async-graphql/en/subscription.html).*
///
2020-03-17 11:11:14 +00:00
/// 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 |
/// | desc | Object description | string | Y |
///
/// # Field parameters
///
/// | Attribute | description | Type | Optional |
/// |-------------|---------------------------|----------|----------|
/// | name | Field name | string | Y |
/// | desc | Field description | string | Y |
/// | deprecation | Field deprecation reason | string | Y |
2020-05-01 23:57:34 +00:00
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
/// | feature | It's like a `#[cfg(feature = "foo")]` attribute but instead of not compiling this field it will just return a proper `FieldError` to tell you this feature is not enabled | string ("feature1,feature2") | Y |
2020-03-17 11:11:14 +00:00
///
/// # Field argument parameters
///
2020-07-07 08:41:29 +00:00
/// | 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 |
2020-03-17 11:11:14 +00:00
///
/// # Examples
///
/// ```rust
2020-03-17 11:11:14 +00:00
/// use async_graphql::*;
/// use futures::{Stream, StreamExt};
2020-03-17 11:11:14 +00:00
///
/// struct SubscriptionRoot;
///
/// #[Subscription]
2020-03-17 11:11:14 +00:00
/// impl SubscriptionRoot {
/// async fn value(&self, condition: i32) -> impl Stream<Item = i32> {
/// // Returns the number from 0 to `condition`.
/// futures::stream::iter(0..condition)
2020-03-17 11:11:14 +00:00
/// }
/// }
/// ```
pub use async_graphql_derive::Subscription;
2020-04-17 03:06:33 +00:00
/// Define a Scalar
///
/// # Macro parameters
///
/// | Attribute | description | Type | Optional |
/// |-------------|---------------------------|----------|----------|
/// | name | Scalar name | string | Y |
/// | desc | Scalar description | string | Y |
///
pub use async_graphql_derive::Scalar;
2020-08-09 04:35:15 +00:00
/// Define a merged object with multiple object types.
///
/// *[See also the Book](https://async-graphql.github.io/async-graphql/en/merging_objects.html).*
///
2020-08-10 06:57:45 +00:00
/// # Macro parameters
///
/// | Attribute | description | Type | Optional |
/// |---------------|---------------------------|----------|----------|
/// | name | Object name | string | Y |
/// | desc | Object description | 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 |
///
2020-08-09 04:35:15 +00:00
/// # Examples
///
/// ```rust
/// use async_graphql::*;
///
/// #[derive(SimpleObject)]
2020-08-09 04:35:15 +00:00
/// struct Object1 {
/// a: i32,
/// }
///
/// #[derive(SimpleObject)]
2020-08-09 04:35:15 +00:00
/// struct Object2 {
/// b: i32,
/// }
///
/// #[derive(SimpleObject)]
2020-08-09 04:35:15 +00:00
/// struct Object3 {
/// c: i32,
/// }
///
/// #[derive(MergedObject)]
2020-08-09 04:35:15 +00:00
/// struct MyObj(Object1, Object2, Object3);
///
2020-08-10 06:11:46 +00:00
/// let obj = MyObj(Object1 { a: 10 }, Object2 { b: 20 }, Object3 { c: 30 });
2020-08-09 04:35:15 +00:00
/// ```
pub use async_graphql_derive::MergedObject;
2020-08-27 07:35:48 +00:00
/// Define a merged subscription with multiple subscription types.
///
/// *[See also the Book](https://async-graphql.github.io/async-graphql/en/merging_objects.html).*
///
2020-08-27 07:35:48 +00:00
/// # Macro parameters
///
/// | Attribute | description | Type | Optional |
/// |---------------|---------------------------|----------|----------|
/// | name | Object name | string | Y |
/// | desc | Object description | string | Y |
///
/// # Examples
///
/// ```rust
/// use async_graphql::*;
/// use futures::Stream;
///
/// #[derive(Default)]
/// struct Subscription1;
///
/// #[Subscription]
2020-08-27 07:35:48 +00:00
/// impl Subscription1 {
/// async fn events1(&self) -> impl Stream<Item = i32> {
/// futures::stream::iter(0..10)
/// }
/// }
///
/// #[derive(Default)]
/// struct Subscription2;
///
/// #[Subscription]
2020-08-27 07:35:48 +00:00
/// impl Subscription2 {
/// async fn events2(&self) -> impl Stream<Item = i32> {
/// futures::stream::iter(10..20)
/// }
/// }
///
/// #[derive(MergedSubscription, Default)]
2020-08-27 07:35:48 +00:00
/// struct Subscription(Subscription1, Subscription2);
/// ```
pub use async_graphql_derive::MergedSubscription;