Update docs
This commit is contained in:
parent
fbfc1ff8b2
commit
0824b6cc23
|
@ -1,6 +1,6 @@
|
||||||
# Context
|
# Context
|
||||||
|
|
||||||
The main goal of `Context` is to acquire global data attached to Schema. **Note that if the return value of resolve function is borrowed from `Context`, you need to explictly 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 need to explictly state the lifetime of the argument.**
|
||||||
|
|
||||||
The following example shows how to borrow data in `Context`.
|
The following example shows how to borrow data in `Context`.
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ Relay's cursor connection specification is defined to provide a consistent metho
|
||||||
It is simple to define a cursor connection in `Async-GraphQL`
|
It is simple to define a cursor connection in `Async-GraphQL`
|
||||||
|
|
||||||
1. Implement `async_graphql::DataSource` and write the `query_operation` function.
|
1. Implement `async_graphql::DataSource` and write the `query_operation` function.
|
||||||
2. Call `DataSource::query` in the field's resolve function and return the result.
|
2. Call `DataSource::query` in the field's resolver function and return the result.
|
||||||
|
|
||||||
Here is a simple data source that returns continuous integers:
|
Here is a simple data source that returns continuous integers:
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Different from `SimpleObject`, `Object` must have Resolve defined for each field in `impl`.
|
Different from `SimpleObject`, `Object` must have Resolve defined for each field in `impl`.
|
||||||
|
|
||||||
**A Resolve 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`, second being optional `Context` and 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 occrs and error message will be send to query result.
|
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 occrs and error message will be send to query result.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# SimpleObject
|
# SimpleObject
|
||||||
|
|
||||||
`SimpleObject` directly map all field of a struct to GraphQL object, you cannot define a Resolve function on it.
|
`SimpleObject` directly map all field of a struct to GraphQL object, you cannot define a resolver function on it.
|
||||||
|
|
||||||
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 defined an object `MyObject`, including field `a` and `b`. `c` will be not mapped to GraphQL as it is labelled as `#[field(skip)]`
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## Query root object
|
## Query root object
|
||||||
|
|
||||||
The query root object is a GraphQL object with a definition similar to other objects. Resolve 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
|
```rust
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Subscription
|
# Subscription
|
||||||
|
|
||||||
The definition of the subscription root object is slightly different from other root objects. Its Resolve 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, 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
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
- [输入值校验器](input_value_validators.md)
|
- [输入值校验器](input_value_validators.md)
|
||||||
- [查询缓存控制](cache_control.md)
|
- [查询缓存控制](cache_control.md)
|
||||||
- [游标连接(Cursor Connections)](cursor_connections.md)
|
- [游标连接(Cursor Connections)](cursor_connections.md)
|
||||||
|
- [错误扩展](error_extensions.md)
|
||||||
- [Apollo Tracing支持](apollo_tracing.md)
|
- [Apollo Tracing支持](apollo_tracing.md)
|
||||||
- [集成到WebServer](integrations.md)
|
- [集成到WebServer](integrations.md)
|
||||||
- [Warp](integrations_to_warp.md)
|
- [Warp](integrations_to_warp.md)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
生产环境下通常依赖缓存来提高性能。
|
生产环境下通常依赖缓存来提高性能。
|
||||||
|
|
||||||
一个GraphQL查询会调用多个Resolve函数,每个Resolve函数都能够具有不同的缓存定义。有的可能缓存几秒钟,有的可能缓存几个小时,有的可能所有用户都相同,有的可能每个会话都不同。
|
一个GraphQL查询会调用多个Resolver函数,每个Resolver函数都能够具有不同的缓存定义。有的可能缓存几秒钟,有的可能缓存几个小时,有的可能所有用户都相同,有的可能每个会话都不同。
|
||||||
|
|
||||||
`Async-graphql`提供一种机制允许定义结果的缓存时间和作用域。
|
`Async-graphql`提供一种机制允许定义结果的缓存时间和作用域。
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# 查询上下文(Context)
|
# 查询上下文(Context)
|
||||||
|
|
||||||
查询上下文(Context)的主要作用是获取附加到Schema的全局数据,**需要注意的是,如果你的Resolve函数返回的数据借用了Context内保存的数据,需要明确指定生命周期参数**。
|
查询上下文(Context)的主要作用是获取附加到Schema的全局数据,**需要注意的是,如果你的Resolver函数返回的数据借用了Context内保存的数据,需要明确指定生命周期参数**。
|
||||||
|
|
||||||
下面是一个返回值借用Context内数据的例子:
|
下面是一个返回值借用Context内数据的例子:
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ Relay定义了一套游标连接规范,以提供一致性的分页查询方式
|
||||||
在`Async-graphql`中定义一个连接非常简单,只需要两步:
|
在`Async-graphql`中定义一个连接非常简单,只需要两步:
|
||||||
|
|
||||||
1. 实现`async_graphql::DataSource`,重写`query_operation`函数。
|
1. 实现`async_graphql::DataSource`,重写`query_operation`函数。
|
||||||
2. 在字段的Resolve函数中调用`DataSource::query`函数并传递响应参数。
|
2. 在字段的Resolver函数中调用`DataSource::query`函数并传递响应参数。
|
||||||
|
|
||||||
下面是一个简单的获取连续整数的数据源:
|
下面是一个简单的获取连续整数的数据源:
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
# 对象(Object)
|
# 对象(Object)
|
||||||
|
|
||||||
和简单对象不同,对象必须为所有的字段定义Resolve函数,Resolve函数定义在impl块中。
|
和简单对象不同,对象必须为所有的字段定义Resolver函数,Resolver函数定义在impl块中。
|
||||||
|
|
||||||
**一个Resolve函数必须是异步的,它的第一个参数必须是`&self`,第二个参数是可选的`Context`,接下来是字段的参数。**
|
**一个Resolver函数必须是异步的,它的第一个参数必须是`&self`,第二个参数是可选的`Context`,接下来是字段的参数。**
|
||||||
|
|
||||||
Resolve函数用于计算字段的值,你可以执行一个数据库查询,并返回查询结果。**函数的返回值是字段的类型**,你也可以返回一个`async_graphql::FieldResult`类型,这样能够返回一个错误,这个错误信息将输出到查询结果中。
|
Resolver函数用于计算字段的值,你可以执行一个数据库查询,并返回查询结果。**函数的返回值是字段的类型**,你也可以返回一个`async_graphql::FieldResult`类型,这样能够返回一个错误,这个错误信息将输出到查询结果中。
|
||||||
|
|
||||||
在查询数据库时,你可能需要一个数据库连接池对象,这个对象是个全局的,你可以在创建Schema的时候,用`SchemaBuilder::data`函数设置`Schema`数据, 用`Context::data`函数设置`Context`数据。下面的`value_from_db`字段展示了如何从`Context`中获取一个数据库连接。
|
在查询数据库时,你可能需要一个数据库连接池对象,这个对象是个全局的,你可以在创建Schema的时候,用`SchemaBuilder::data`函数设置`Schema`数据, 用`Context::data`函数设置`Context`数据。下面的`value_from_db`字段展示了如何从`Context`中获取一个数据库连接。
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# 接口(Interface)
|
# 接口(Interface)
|
||||||
|
|
||||||
接口用于抽象具有特定字段集合的对象,`Async-graphql`内部实现实际上是一个包装器,包装器转发接口上定义的Resolve函数到实现该接口的对象,所以接口类型所包含的字段类型,参数都必须和实现该接口的对象完全匹配。
|
接口用于抽象具有特定字段集合的对象,`Async-graphql`内部实现实际上是一个包装器,包装器转发接口上定义的Resolver函数到实现该接口的对象,所以接口类型所包含的字段类型,参数都必须和实现该接口的对象完全匹配。
|
||||||
|
|
||||||
`Async-graphql`自动实现了对象到接口的转换,把一个对象类型转换为接口类型只需要调用`Into::into`。
|
`Async-graphql`自动实现了对象到接口的转换,把一个对象类型转换为接口类型只需要调用`Into::into`。
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# 简单对象(SimpleObject)
|
# 简单对象(SimpleObject)
|
||||||
|
|
||||||
简单对象是把Rust结构的所有字段都直接映射到GraphQL对象,不支持定义单独的Resolve函数。
|
简单对象是把Rust结构的所有字段都直接映射到GraphQL对象,不支持定义单独的Resolver函数。
|
||||||
|
|
||||||
下面的例子定义了一个名称为MyObject的对象,包含字段`a`和`b`,`c`由于标记为`#[field(skip)]`,所以不会映射到GraphQL。
|
下面的例子定义了一个名称为MyObject的对象,包含字段`a`和`b`,`c`由于标记为`#[field(skip)]`,所以不会映射到GraphQL。
|
||||||
|
|
||||||
|
|
|
@ -1 +1,200 @@
|
||||||
# 错误扩展
|
# 错误扩展
|
||||||
|
|
||||||
|
引用 [graphql-spec](https://spec.graphql.org/June2018/#example-fce18)
|
||||||
|
|
||||||
|
> GraphQL服务可以通过扩展提供错误的附加条目。
|
||||||
|
> 该条目(如果设置)必须是一个映射作为其值,用于附加错误的其它信息。
|
||||||
|
|
||||||
|
## 示例
|
||||||
|
|
||||||
|
我建议您查看此 [错误扩展示例](https://github.com/async-graphql/examples/blob/master/actix-web/error-extensions/src/main.rs) 作为快速入门。
|
||||||
|
|
||||||
|
## 一般概念
|
||||||
|
|
||||||
|
在`Async-graphql`中,所有面向用户的错误都强制转换为`FieldError`类型,默认情况下会提供
|
||||||
|
由`std:::fmt::Display`暴露的错误消息。但是,`FieldError`实际上提供了一个额外的
|
||||||
|
字段`Option<serde_json::Value>`,如果它是一个`serde_json::Map`,则可以扩展错误的信息。
|
||||||
|
|
||||||
|
Resolver函数类似这样:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
async fn parse_with_extensions(&self) -> Result<i32, FieldError> {
|
||||||
|
let my_extension = json!({ "details": "CAN_NOT_FETCH" });
|
||||||
|
Err(FieldError("MyMessage", Some(my_extension)))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
然后可以返回如下响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"message": "MyMessage",
|
||||||
|
"locations": [ ... ],
|
||||||
|
"path": [ ... ],
|
||||||
|
"extensions": {
|
||||||
|
"details": "CAN_NOT_FETCH",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## ErrorExtensions
|
||||||
|
|
||||||
|
手动构造新的`FieldError`很麻烦。这就是为什么`Async-graphql`提供
|
||||||
|
两个方便特性,可将您的错误转换为适当的`FieldError`扩展。
|
||||||
|
|
||||||
|
扩展任何错误的最简单方法是对错误调用`extend_with`。
|
||||||
|
这将把任何错误转换为具有给定扩展信息的`FieldError`。
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
async fn parse_with_extensions(&self) -> FieldResult<i32> {
|
||||||
|
Ok("234a"
|
||||||
|
.parse()
|
||||||
|
.map_err(|err: ParseIntError| err.extend_with(|_err| json!({"code": 404})))?)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 为自定义错误实现ErrorExtensions
|
||||||
|
|
||||||
|
你也可以给自己的错误类型实现`ErrorExtensions`:
|
||||||
|
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[macro_use]
|
||||||
|
extern crate thiserror;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum MyError {
|
||||||
|
#[error("Could not find resource")]
|
||||||
|
NotFound,
|
||||||
|
|
||||||
|
#[error("ServerError")]
|
||||||
|
ServerError(String),
|
||||||
|
|
||||||
|
#[error("No Extensions")]
|
||||||
|
ErrorWithoutExtensions,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorExtensions for MyError {
|
||||||
|
// lets define our base extensions
|
||||||
|
fn extend(&self) -> FieldError {
|
||||||
|
let extensions = match self {
|
||||||
|
MyError::NotFound => json!({"code": "NOT_FOUND"}),
|
||||||
|
MyError::ServerError(reason) => json!({ "reason": reason }),
|
||||||
|
MyError::ErrorWithoutExtensions => {
|
||||||
|
json!("This will be ignored since it does not represent an object.")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FieldError(format!("{}", self), Some(extensions))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
您只需要对错误调用`extend`即可将错误与其提供的扩展信息一起传递,或者通过`extend_with`进一步扩展错误信息。
|
||||||
|
|
||||||
|
```rust
|
||||||
|
async fn parse_with_extensions_result(&self) -> FieldResult<i32> {
|
||||||
|
// Err(MyError::NotFound.extend())
|
||||||
|
// OR
|
||||||
|
Err(MyError::NotFound.extend_with(|_| json!({ "on_the_fly": "some_more_info" })))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"message": "NotFound",
|
||||||
|
"locations": [ ... ],
|
||||||
|
"path": [ ... ],
|
||||||
|
"extensions": {
|
||||||
|
"code": "NOT_FOUND",
|
||||||
|
"on_the_fly": "some_more_info"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## ResultExt
|
||||||
|
这个特质使您可以直接在结果上调用`extend_err`。因此上面的代码不再那么冗长。
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use async_graphql::*;
|
||||||
|
async fn parse_with_extensions(&self) -> FieldResult<i32> {
|
||||||
|
Ok("234a"
|
||||||
|
.parse()
|
||||||
|
.extend_err(|_| json!({"code": 404}))?)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 链式调用
|
||||||
|
|
||||||
|
由于对所有`&E where E: std::fmt::Display`实现了`ErrorExtensions`和`ResultsExt`,我们可以将扩展链接在一起。
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use async_graphql::*;
|
||||||
|
async fn parse_with_extensions(&self) -> FieldResult<i32> {
|
||||||
|
match "234a".parse() {
|
||||||
|
Ok(n) => Ok(n),
|
||||||
|
Err(e) => Err(e
|
||||||
|
.extend_with(|_| json!({"code": 404}))
|
||||||
|
.extend_with(|_| json!({"details": "some more info.."}))
|
||||||
|
// keys may also overwrite previous keys...
|
||||||
|
.extend_with(|_| json!({"code": 500}))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"message": "MyMessage",
|
||||||
|
"locations": [ ... ],
|
||||||
|
"path": [ ... ],
|
||||||
|
"extensions": {
|
||||||
|
"details": "some more info...",
|
||||||
|
"code": 500,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 陷阱
|
||||||
|
|
||||||
|
Rust的稳定版本还未提供特化功能,这就是为什么`ErrorExtensions`为`&E where E: std::fmt::Display`实现,代替`E:std::fmt::Display`通过提供一些特化功能。
|
||||||
|
|
||||||
|
[Autoref-based stable specialization](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md).
|
||||||
|
|
||||||
|
缺点是下面的代码**不能**编译:
|
||||||
|
|
||||||
|
```rust,ignore,does_not_compile
|
||||||
|
async fn parse_with_extensions_result(&self) -> FieldResult<i32> {
|
||||||
|
// the trait `error::ErrorExtensions` is not implemented
|
||||||
|
// for `std::num::ParseIntError`
|
||||||
|
"234a".parse().extend_err(|_| json!({"code": 404}))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
但这可以通过编译:
|
||||||
|
|
||||||
|
```rust,ignore,does_not_compile
|
||||||
|
async fn parse_with_extensions_result(&self) -> FieldResult<i32> {
|
||||||
|
// does work because ErrorExtensions is implemented for &ParseIntError
|
||||||
|
"234a"
|
||||||
|
.parse()
|
||||||
|
.map_err(|ref e: ParseIntError| e.extend_with(|_| json!({"code": 404})))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# 错误处理
|
# 错误处理
|
||||||
|
|
||||||
Resolve函数可以返回一个FieldResult类型,以下是FieldResult的定义:
|
Resolver函数可以返回一个FieldResult类型,以下是FieldResult的定义:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
type FieldResult<T> = std::result::Result<T, FieldError>;
|
type FieldResult<T> = std::result::Result<T, FieldError>;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## 查询根对象
|
## 查询根对象
|
||||||
|
|
||||||
查询根对象是一个GraphQL对象,定义类似其它对象。查询对象的所有字段Resolve函数是并发执行的。
|
查询根对象是一个GraphQL对象,定义类似其它对象。查询对象的所有字段Resolver函数是并发执行的。
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use async_graphql::*;
|
use async_graphql::*;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# 订阅
|
# 订阅
|
||||||
|
|
||||||
订阅根对象和其它根对象定义稍有不同,它的Resolve函数总是返回一个`Stream`,而字段参数通常作为数据的筛选条件。
|
订阅根对象和其它根对象定义稍有不同,它的Resolver函数总是返回一个`Stream`,而字段参数通常作为数据的筛选条件。
|
||||||
|
|
||||||
下面的例子订阅一个整数流,它每秒产生一个整数,参数`step`指定了整数的步长,默认为1。
|
下面的例子订阅一个整数流,它每秒产生一个整数,参数`step`指定了整数的步长,默认为1。
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user