Improve book and fix serde dependency
This commit is contained in:
parent
b2a0871798
commit
1ef34f2c39
|
@ -22,7 +22,7 @@ async-graphql-derive = { path = "async-graphql-derive", version = "1.17.11" }
|
|||
anyhow = "1.0.26"
|
||||
thiserror = "1.0.11"
|
||||
async-trait = "0.1.30"
|
||||
serde = { version = "1.0.104", features = ["serde_derive"] }
|
||||
serde = { version = "1.0.104", features = ["derive"] }
|
||||
serde_json = "1.0.48"
|
||||
bytes = "0.5.4"
|
||||
Inflector = "0.11.4"
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
authors = ["sunli"]
|
||||
description = "Async-graphql Book"
|
||||
src = "src"
|
||||
language = "zh-CN"
|
||||
language = "en"
|
||||
title = "Async-graphql Book"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Apollo Federation
|
||||
|
||||
`Apollo Federation` is a `GraphQL` API gateway which can combine multiple GraphQL services, allowing each service to implement the subset of the API it is responsible for. You can read more in the [official documentation](https://www.apollographql.com/docs/apollo-server/federation/introduction)。
|
||||
`Apollo Federation` is a `GraphQL` API gateway which can combine multiple GraphQL services, allowing each service to implement the subset of the API it is responsible for. You can read more in the [official documentation](https://www.apollographql.com/docs/apollo-server/federation/introduction).
|
||||
|
||||
`Async-GraphQL` supports all the functionality of `Apollo Federation`, but some modifications to your `Schema` are required.
|
||||
`Async-graphql` supports all the functionality of `Apollo Federation`, but some modifications to your `Schema` are required.
|
||||
|
||||
- You can use the `extends` property declaration on `async_graphql::Object` and `async_graphql::Interface` to extend a type offered by another implementing service.
|
||||
|
||||
|
@ -36,16 +36,16 @@ impl Query {
|
|||
|
||||
**Notice the difference between these three lookup functions, which are all looking for the `User` object.**
|
||||
|
||||
- find_user_by_id
|
||||
- `find_user_by_id`
|
||||
|
||||
Use `id` to find an `User` object, the key for `User` is `id`。
|
||||
Use `id` to find an `User` object, the key for `User` is `id`.
|
||||
|
||||
- find_user_by_id_with_username
|
||||
- `find_user_by_id_with_username`
|
||||
|
||||
Use `id` to find an `User` object, the key for `User` is `id`, and the `username` field value of the `User` object is requested。
|
||||
Use `id` to find an `User` object, the key for `User` is `id`, and the `username` field value of the `User` object is requested.
|
||||
|
||||
- find_user_by_id_and_username
|
||||
- `find_user_by_id_and_username`
|
||||
|
||||
Use `id` and `username` to find an `User` object, the keys for `User` are `id` and `username`。
|
||||
Use `id` and `username` to find an `User` object, the keys for `User` are `id` and `username`.
|
||||
|
||||
For a complete example, refer to: https://github.com/async-graphql/examples/tree/master/federation
|
||||
For a complete example, refer to: <https://github.com/async-graphql/examples/tree/master/federation>.
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
|
||||
Apollo Tracing provides performance analysis results for each step of query. This is an extension to `Schema`, and the performance analysis results are stored in `QueryResponse`.
|
||||
|
||||
To enable the Apollo Tracing extension, add the extension when a `Schema` is created.
|
||||
To enable the Apollo Tracing extension, add the extension when the `Schema` is created.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
use async_graphql::extensions::ApolloTracing;
|
||||
|
||||
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
|
||||
.extension(|| ApolloTracing::default()) // Enable ApolloTracing extension
|
||||
.extension(ApolloTracing::default) // Enable ApolloTracing extension
|
||||
.finish();
|
||||
|
||||
```
|
||||
```
|
||||
|
|
|
@ -4,13 +4,13 @@ Production environments often rely on caching to improve performance.
|
|||
|
||||
A GraphQL query will call multiple resolver functions and each resolver can have a different cache definition. Some may cache for a few seconds, some may cache for a few hours, some may be the same for all users, and some may be different for each session.
|
||||
|
||||
`Async-Graphql` provides a mechanism that allows you to define the cache time and scope for each resolver.
|
||||
`Async-graphql` provides a mechanism that allows you to define the cache time and scope for each resolver.
|
||||
|
||||
You can define cache parameters on the object or on its fields. The following example shows two uses of cache control parameters.
|
||||
|
||||
You can use `max_age` parameters to control the age of the cache (in seconds), and you can also use `public` and `private` to control the scope of the cache. When you do not specify it, the scope will default to `public`.
|
||||
|
||||
lWhen querying multiple resolvers, the results of all cache control parameters will be combined and the `max_age` minimum value will be taken. If the scope of any object or field is `private`, the result will be `private`.
|
||||
when querying multiple resolvers, the results of all cache control parameters will be combined and the `max_age` minimum value will be taken. If the scope of any object or field is `private`, the result will be `private`.
|
||||
|
||||
We can use `QueryResponse` to get a merged cache control result from a query result, and call `CacheControl::value` to get the corresponding HTTP header.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Context
|
||||
|
||||
The main goal of `Context` is to acquire global data attached to Schema. **Note that if the return value of resolver function is borrowed from `Context`, you need to explicitly state the lifetime of the argument.**
|
||||
The main goal of `Context` is to acquire global data attached to Schema. **Note that if the return value of resolver function is borrowed from `Context`, you will need to explicitly state the lifetime of the argument.**
|
||||
|
||||
The following example shows how to borrow data in `Context`.
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Cursor connections
|
||||
|
||||
Relay's cursor connection specification is defined to provide a consistent method for query paging. For more details on the specification see the [GraphQL Cursor Connections Specification](https://facebook.github.io/relay/graphql/connections.htm)。
|
||||
Relay's cursor connection specification is designed to provide a consistent method for query paging. For more details on the specification see the [GraphQL Cursor Connections Specification](https://facebook.github.io/relay/graphql/connections.htm)。
|
||||
|
||||
Define a cursor connection in `async-graphql` is very simple, you just call the `connection::query` function and query data in closure.
|
||||
Defining a cursor connection in `async-graphql` is very simple, you just call the `connection::query` function and query data in the closure.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
@ -42,4 +42,4 @@ impl Query {
|
|||
}
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
# Custom scalars
|
||||
|
||||
In `Async-GraphQL` most common scalar types are built in, but you can also create your own scalar types.
|
||||
In `Async-graphql` most common scalar types are built in, but you can also create your own scalar types.
|
||||
|
||||
Using `async-graphql::Scalar`, you can add support for a scalar when you implement it. You only need to implement parsing and output functions.
|
||||
|
||||
The following example defines a 64-bit integer scalar where its input and output are strings. (Note: `Async-graphQL` already supports 64-bit integers and uses strings as input and output.)
|
||||
The following example defines a 64-bit integer scalar where its input and output are strings. (Note: `Async-graphql` already supports 64-bit integers and uses strings as input and output.)
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
||||
|
||||
struct StringNumber(i64);
|
||||
|
||||
#[Scalar]
|
||||
|
@ -28,5 +27,4 @@ impl ScalarType for StringNumber {
|
|||
Value::String(self.0.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Default value
|
||||
|
||||
You can define default values for input value types.
|
||||
The following shows how to define default values for different types.
|
||||
Below are some examples.
|
||||
|
||||
## Object field
|
||||
|
||||
|
@ -57,4 +57,4 @@ struct MyInputObject {
|
|||
#[field(default = "my_default()")]
|
||||
value3: i32,
|
||||
}
|
||||
```
|
||||
```
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
# Object
|
||||
|
||||
Different from `SimpleObject`, `Object` must have Resolve defined for each field in `impl`.
|
||||
Different from `SimpleObject`, `Object` must have a resolver defined for each field in its `impl`.
|
||||
|
||||
**A resolver function has to be asynchronous. The first argument has to be `&self`, second being optional `Context` and followed by field arguments.**
|
||||
**A resolver function has to be asynchronous. The first argument has to be `&self`, the second is an optional `Context` and it is followed by field arguments.**
|
||||
|
||||
Resolve is used to get the value of the field. You can query a database and return the result. **The return type of the function is the type of the field.** You can also return a `async_graphql::FieldResult` so to return an error if it occurs an error message will be sent to query result.
|
||||
The resolvers is used to get the value of the field. For example, you can query a database and return the result. **The return type of the function is the type of the field.** You can also return a `async_graphql::FieldResult` to return an error if it occurs. The error message will then be sent to query result.
|
||||
|
||||
When querying a database, you may need a global data base connection pool.
|
||||
When creating `Schema`, you can use `SchemaBuilder::data` to setup `Schema` data, and `Context::data` to setup `Context`data.
|
||||
The following `value_from_db` function showed how to retrieve a database connection from `Context`.
|
||||
You may need access to global data in your query, for example a database connection pool.
|
||||
When creating your `Schema`, you can use `SchemaBuilder::data` to configure the global data, and `Context::data` to configure `Context` data.
|
||||
The following `value_from_db` function shows how to retrieve a database connection from `Context`.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
It's easy to define an `Enum`, here we have an example:
|
||||
|
||||
**Async-graphql can automatically change the name of each item to GraphQL's CONSTANT_CASE convension, you can also use `name` to rename.**
|
||||
**Async-graphql will automatically change the name of each item to GraphQL's CONSTANT_CASE convention. You can use `name` to rename.**
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
@ -19,4 +19,4 @@ pub enum Episode {
|
|||
#[item(name="AAA", desc = "Released in 1983.")]
|
||||
Jedi,
|
||||
}
|
||||
```
|
||||
```
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# InputObject
|
||||
|
||||
<!--Input Object and SimpleObject inconsistant space.-->
|
||||
You can define an `Object` as argument, GraphQL calls it `InputObject`.
|
||||
The definition of `InputObject` is similar to [SimpleObject](define_simple_object.md).
|
||||
However, `SimpleObject` can only be used for output and `InputObject` can only be used as input.
|
||||
You can use an `Object` as an argument, and GraphQL calls it an `InputObject`.
|
||||
The definition of `InputObject` is similar to [SimpleObject](define_simple_object.md), but
|
||||
`SimpleObject` can only be used as output and `InputObject` can only be used as input.
|
||||
|
||||
`InputObject` don't need a `#[field]` for each field, every field is `InputValue`.
|
||||
But you can add optional `#[field]` to add description or rename the field.
|
||||
`InputObject` doesn't need a `#[field]` for each field, every field is an `InputValue`.
|
||||
You can add optional `#[field]` attributes to add descriptions or rename the field.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
@ -28,4 +28,4 @@ impl Mutation {
|
|||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
# Interface
|
||||
|
||||
`Interface` is used to abstract `Object`s with common fields.
|
||||
`Async-graphql` implemented it as a wrapper.
|
||||
The wrapper will forward Resolve to the `Object` that implemented this `Interface`.
|
||||
Therefore, the `Object`'s fields' type, arguments must match with the `Interface`'s.
|
||||
`Async-graphql` implements it as a wrapper.
|
||||
The wrapper will forward field resolution to the `Object` that implements this `Interface`.
|
||||
Therefore, the `Object`'s fields' type and arguments must match with the `Interface`'s.
|
||||
|
||||
`Async-graphql` implemented auto conversion from `Object` to `Interface`, you only need to call `Into::into`.
|
||||
`Async-graphql` implements auto conversion from `Object` to `Interface`, you only need to call `Into::into`.
|
||||
|
||||
Interface fields names transforms to camelCase in schema definition.
|
||||
If you need e.g. snake_cased GraphQL field name, you can use both the `name` and `method` attribute.
|
||||
Interface field names are transformed to camelCase for the schema definition.
|
||||
If you need e.g. a snake_cased GraphQL field name, you can use both the `name` and `method` attributes.
|
||||
|
||||
- When the `name` and `method` exist together, the `name` is the GraphQL field name and the `method` is the resolver function name.
|
||||
- When `name` and `method` exist together, `name` is the GraphQL field name and the `method` is the resolver function name.
|
||||
- When only `name` exists, `name.to_camel_case()` is the GraphQL field name and the `name` is the resolver function name.
|
||||
|
||||
```rust
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Schema
|
||||
|
||||
After defining the basic types, you need to define a schema to combine them. The schema consists of three types: a query object, mutation object, and subscription object, where the mutation object and subscription object are optional.
|
||||
After defining the basic types, you need to define a schema to combine them. The schema consists of three types: a query object, a mutation object, and a subscription object, where the mutation object and subscription object are optional.
|
||||
|
||||
When the schema is created, `Async-Graphql` will traverse all object graphs and register all types. This means that if a GraphQL object is defined but never referenced, then this object will not be exposed in the schema.
|
||||
When the schema is created, `Async-graphql` will traverse all object graphs and register all types. This means that if a GraphQL object is defined but never referenced, this object will not be exposed in the schema.
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# SimpleObject
|
||||
|
||||
`SimpleObject` directly map all field of a struct to GraphQL object, you cannot define a resolver function on it.
|
||||
`SimpleObject` directly maps all the fields of a struct to GraphQL object. You cannot define a resolver function on it - for that, see [Object](define_complex_object.html).
|
||||
|
||||
The example below defined an object `MyObject`, including field `a` and `b`. `c` will be not mapped to GraphQL as it is labelled as `#[field(skip)]`
|
||||
The example below defines an object `MyObject` which includes the fields `a` and `b`. `c` will be not mapped to GraphQL as it is labelled as `#[field(skip)]`
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
# Union
|
||||
|
||||
The definition of `Union` is similar to `Interface`'s, **but no field allowed.**.
|
||||
The implemention is quite similar for `Async-graphql`.
|
||||
From `Async-graphql`'s perspective, `Union` is a subset of `Interface`.
|
||||
The definition of a `Union` is similar to an `Interface`, **but with no fields allowed.**.
|
||||
The implementation is quite similar for `Async-graphql`; from `Async-graphql`'s perspective, `Union` is a subset of `Interface`.
|
||||
|
||||
The following example modified the definition of `Interface` a little bit and removed fields.
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Error extensions
|
||||
To quote the [graphql-spec](https://spec.graphql.org/June2018/#example-fce18):
|
||||
> GraphQL services may provide an additional entry to errors with key extensions.
|
||||
> This entry, if set, must have a map as its value. This entry is reserved for implementors to add
|
||||
> This entry, if set, must have a map as its value. This entry is reserved for implementer to add
|
||||
> additional information to errors however they see fit, and there are no additional restrictions on
|
||||
> its contents.
|
||||
|
||||
|
@ -9,11 +9,11 @@ To quote the [graphql-spec](https://spec.graphql.org/June2018/#example-fce18):
|
|||
I would recommend on checking out this [async-graphql example](https://github.com/async-graphql/examples/blob/master/actix-web/error-extensions/src/main.rs) as a quickstart.
|
||||
|
||||
## General Concept
|
||||
In async-graphql all user-facing errors are cast to the `FieldError` type which by default provides
|
||||
the error message exposed by `std::fmt::Display`. However `FieldError` actually provides an additional
|
||||
field `Option<serde_json::Value>` which - if some valid `serde_json::Map` - will be exposed as the extensions key to any error.
|
||||
In `async-graphql` all user-facing errors are cast to the `FieldError` type which by default provides
|
||||
the error message exposed by `std::fmt::Display`. However `FieldError` also provides an additional
|
||||
field `Option<serde_json::Value>` which - if given some valid `serde_json::Map` - will be exposed as the extensions key to any error.
|
||||
|
||||
A resolver like this:
|
||||
A resolver looks like this:
|
||||
|
||||
```rust
|
||||
async fn parse_with_extensions(&self) -> Result<i32, FieldError> {
|
||||
|
@ -41,7 +41,7 @@ may then return a response like this:
|
|||
|
||||
|
||||
## ErrorExtensions
|
||||
Constructing new `FieldError`s by hand quickly becomes tedious. That is why async_graphql provides
|
||||
Constructing new `FieldError`s by hand quickly becomes tedious. That is why `async-graphql` provides
|
||||
two convenience traits for casting your errors to the appropriate `FieldError` with
|
||||
extensions.
|
||||
|
||||
|
@ -62,8 +62,7 @@ If you find yourself attaching extensions to your errors all over the place you
|
|||
implementing the trait on your custom error type directly.
|
||||
|
||||
```rust
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MyError {
|
||||
|
@ -102,7 +101,6 @@ async fn parse_with_extensions_result(&self) -> FieldResult<i32> {
|
|||
// OR
|
||||
Err(MyError::NotFound.extend_with(|_| json!({ "on_the_fly": "some_more_info" })))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```json
|
||||
|
@ -119,12 +117,8 @@ async fn parse_with_extensions_result(&self) -> FieldResult<i32> {
|
|||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## ResultExt
|
||||
This trait enables you to call `extend_err` directly on results. So the above code becomes less verbose.
|
||||
|
||||
|
@ -176,7 +170,7 @@ Expected response:
|
|||
### Pitfalls
|
||||
Rust does not provide stable trait specialization yet.
|
||||
That is why `ErrorExtensions` is actually implemented for `&E where E: std::fmt::Display`
|
||||
instead of `E: std::fmt::Display` to provide some specialization through
|
||||
instead of `E: std::fmt::Display`. Some specialization is provided through
|
||||
[Autoref-based stable specialization](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md).
|
||||
The disadvantage is that the below code does **NOT** compile:
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
# Error handling
|
||||
|
||||
Resolve can return a `FieldResult`, following is the definition:
|
||||
Resolve can return a `FieldResult`, which has the following definition:
|
||||
|
||||
```rust
|
||||
type FieldResult<T> = std::result::Result<T, FieldError>;
|
||||
```
|
||||
|
||||
Any `Error` that implements `std::fmt::Display` can be converted to `FieldError` and you can extend error message.
|
||||
Any `Error` that implements `std::fmt::Display` can be converted to `FieldError` and you can extend the error message.
|
||||
|
||||
Following example shows how to parse an input string to integer. When parsing failed, it would return error and attach error message.
|
||||
See [ErrorExtensions](error_extensions.md) sections of this book for more details.
|
||||
The following example shows how to parse an input string to an integer. When parsing fails, it will return an error and attach an error message.
|
||||
See the [Error Extensions](error_extensions.md) section of this book for more details.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
# Input value validators
|
||||
|
||||
|
||||
Arguments to a query ([InputObject](define_input_object.md)) are called `Input Objects` in GraphQL. If the provided input type does not match for a query, the query will return a type mismatch error. But sometimes we want to provide more restrictions on specific types of values. For example, we might want to require that an argument is a valid email address. Async-graphql provides an input validators to solve this problem.
|
||||
Arguments to a query ([InputObject](define_input_object.md)) are called `Input Objects` in GraphQL. If the provided input type does not match for a query, the query will return a type mismatch error. But sometimes we want to provide more restrictions on specific types of values. For example, we might want to require that an argument is a valid email address. `Async-graphql` provides an input validators to solve this problem.
|
||||
|
||||
An input validator can be combined via `and` and `or` operators.
|
||||
|
||||
|
||||
The following is an input validator which checks that a `String` is a valid Email or MAC address:
|
||||
|
||||
|
||||
|
@ -22,7 +21,6 @@ impl Query {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
The following example verifies that the `i32` parameter `a` is greater than 10 and less than 100, or else equal to 0:
|
||||
|
||||
```rust
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# Integrations
|
||||
|
||||
`Async-Graphql` supports several common Rust web servers.
|
||||
`Async-graphql` supports several common Rust web servers.
|
||||
|
||||
- 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)
|
||||
|
||||
**Even if the server you are currently using is not in the above list, it is quite simple to implement similar functionality yourself**
|
||||
**Even if the server you are currently using is not in the above list, it is quite simple to implement similar functionality yourself.**
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Actix-web
|
||||
|
||||
`Async-graphql-actix-web` provides an implementation of `actix_web::FromRequest` for `GQLRequest`. This is actually an abstraction around `QueryBuilder` and you can call `GQLRequest::into_inner` to convert it into a `QueryBuilder`。
|
||||
`Async-graphql-actix-web` provides an implementation of `actix_web::FromRequest` for `GQLRequest`. This is actually an abstraction around `QueryBuilder` and you can call `GQLRequest::into_inner` to convert it into a `QueryBuilder`.
|
||||
|
||||
`WSSubscription` is an Actor that supports WebSocket subscriptions。
|
||||
`WSSubscription` is an Actor that supports WebSocket subscriptions.
|
||||
|
||||
## Request example
|
||||
|
||||
|
|
|
@ -35,4 +35,4 @@ cd benchmark
|
|||
cargo bench
|
||||
```
|
||||
|
||||
Now HTML report is available at `benchmark/target/criterion/report`
|
||||
Now a HTML report is available at `benchmark/target/criterion/report`.
|
||||
|
|
|
@ -18,9 +18,9 @@ impl Query {
|
|||
}
|
||||
```
|
||||
|
||||
Instead, the `#[derive(GQLMergedObject)]` macro allows you to split an object's resolvers across multiple file by merging 2 or more `#[Object]` implementations into one.
|
||||
Instead, the `#[derive(GQLMergedObject)]`/`#[MergedObject]` macro allows you to split an object's resolvers across multiple modules or files by merging 2 or more `#[Object]` implementations into one.
|
||||
|
||||
**Tip:** Every `#[Object]` needs a unique name even in a GQLMergedObject so make sure to give each object your merging it's own name.
|
||||
**Tip:** Every `#[Object]` needs a unique name, even in a `GQLMergedObject`, so make sure to give each object you're merging its own name.
|
||||
|
||||
**Note:** This works for queries and mutations. For subscriptions, see "Merging Subscriptions" below.
|
||||
|
||||
|
@ -51,7 +51,7 @@ let schema = Schema::new(
|
|||
|
||||
# Merging Subscriptions
|
||||
|
||||
Along with `GQLMergedObject`, you can derive `GQLMergedSubscription` to merge separate `#[Subscription]` blocks.
|
||||
Along with `GQLMergedObject`, you can derive `GQLMergedSubscription` or use `#[MergedSubscription]` to merge separate `#[Subscription]` blocks.
|
||||
|
||||
Like merging Objects, each subscription block requires a unique name.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Two ways to define types
|
||||
|
||||
I think you have discovered that defining a GraphqlQL type can be use attribute macro or derive.
|
||||
I think you have discovered that GraphQL types can be defined using both an attribute macro and a derive.
|
||||
|
||||
The following is the corresponding table:
|
||||
|
||||
|
@ -14,7 +14,7 @@ The following is the corresponding table:
|
|||
|Merged Object|MergedObject|GQLMergedObject|
|
||||
|Merged Subscription|MergedSubscription|GQLMergedSubscription|
|
||||
|
||||
The advantage of attribute macro is that you can provide some parameters at the same time, for example:
|
||||
The advantage of the attribute macro is that you can provide parameters at the same time, for example:
|
||||
|
||||
```rust
|
||||
#[SimpleObject(name = "ABC")]
|
||||
|
@ -23,7 +23,7 @@ struct MyObject {
|
|||
}
|
||||
```
|
||||
|
||||
**But it does not support conditional compilation**, for example:
|
||||
**However, attribute macros do not support conditional compilation**. The following does not work:
|
||||
|
||||
```rust
|
||||
#[SimpleObject]
|
||||
|
@ -36,7 +36,7 @@ struct MyObject {
|
|||
}
|
||||
```
|
||||
|
||||
**Derive can support conditional compilation**, but it needs to provide parameters separately, for example:
|
||||
Deriving, on the other hand, does support conditional compilation, but as derive macros can't take parameters you need to provide them separately. For example:
|
||||
|
||||
```rust
|
||||
#[derive(SimpleObject)]
|
||||
|
@ -46,4 +46,4 @@ struct MyObject {
|
|||
}
|
||||
```
|
||||
|
||||
_Which way to define the type is up to you, I prefer to use derive._
|
||||
_Which way you use to define types is up to you, personally I prefer to use derive._
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
## Query root object
|
||||
|
||||
The query root object is a GraphQL object with a definition similar to other objects. resolver functions for all fields of the query object are executed concurrently.
|
||||
|
||||
The query root object is a GraphQL object with a definition similar to other objects. Resolver functions for all fields of the query object are executed concurrently.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
async-graphql = "1.11.0"
|
||||
async-graphql-actix-web = "1.3.0" # If you need to integrate into actix-web
|
||||
async-graphql-warp = "1.3.0" # If you need to integrate into warp
|
||||
async-graphql-tide = "1.2.0" # If you need to integrate into tide
|
||||
async-graphql = "1.17.15"
|
||||
async-graphql-actix-web = "1.17.3" # If you need to integrate into actix-web
|
||||
async-graphql-warp = "1.17.3" # If you need to integrate into warp
|
||||
async-graphql-tide = "1.17.9" # If you need to integrate into tide
|
||||
```
|
||||
|
||||
## Write a Schema
|
||||
|
@ -30,12 +30,11 @@ impl Query {
|
|||
a + b
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Execute the query
|
||||
|
||||
In our example, there is only Query without Mutation and Subscription, so we create the Schema with `EmptyMutation` and `EmptySubscription`, and then call `Schema::execute` to execute the Query.
|
||||
In our example, there is only a Query without a Mutation or Subscription, so we create the Schema with `EmptyMutation` and `EmptySubscription`, and then call `Schema::execute` to execute the Query.
|
||||
|
||||
```rust
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
|
@ -44,7 +43,7 @@ let res = schema.execute("{ add(a: 10, b: 20) }");
|
|||
|
||||
## Output the query results as JSON
|
||||
|
||||
Query returns `async_graphql::Result` with `async_graphql::http::GQLResponse ` wrapped, can be directly converted to JSON.
|
||||
`Schema::execute` returns `async_graphql::Result` with `async_graphql::http::GQLResponse` wrapped, and it can be directly converted to JSON.
|
||||
|
||||
```rust
|
||||
let json = serde_json::to_string(&async_graphql::http::GQLResponse(res));
|
||||
|
@ -52,4 +51,4 @@ let json = serde_json::to_string(&async_graphql::http::GQLResponse(res));
|
|||
|
||||
## Web server integration
|
||||
|
||||
Please refer to https://github.com/async-graphql/examples.
|
||||
Please refer to <https://github.com/async-graphql/examples>.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Subscription
|
||||
|
||||
The definition of the subscription root object is slightly different from other root objects. Its resolver function always returns a Stream, and the field parameters are usually used as data filtering conditions.
|
||||
The definition of the subscription root object is slightly different from other root objects. Its resolver function always returns a [Stream](https://docs.rs/futures-core/~0.3/futures_core/stream/trait.Stream.html), and the field parameters are usually used as data filtering conditions.
|
||||
|
||||
The following example subscribes to an integer stream, which generates one integer per second. The parameter step specifies the integer step size with a default of 1
|
||||
The following example subscribes to an integer stream, which generates one integer per second. The parameter `step` specifies the integer step size with a default of 1.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Type System
|
||||
|
||||
`Async-graphql` implemented conversion from GraphQL Object to Rust struct, and it's easy to use.
|
||||
`Async-graphql` implements conversions from GraphQL Objects to Rust structs, and it's easy to use.
|
||||
|
|
|
@ -12,14 +12,11 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div>
|
||||
<a href="en/index.html">English</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="zh-CN/index.html">简体中文</a>
|
||||
</div>
|
||||
|
||||
<h1>Async-graphql Book</h1>
|
||||
<p>This book is available in multiple languages:</p>
|
||||
<ul>
|
||||
<li><a href="en/index.html">English</a></li>
|
||||
<li><a href="zh-CN/index.html">简体中文</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue