Update Book

This commit is contained in:
Sunli 2020-09-13 12:12:32 +08:00
parent 3b372edfd7
commit b68d4147bc
38 changed files with 84 additions and 93 deletions

View File

@ -36,16 +36,6 @@
This crate uses `#![forbid(unsafe_code)]` to ensure everything is implemented in 100% Safe Rust.
## Stability: Unstable & Experimental
__This project doesn't currently follow [Semantic Versioning (SemVer)](https://semver.org/), and there can be breaking changes on any version numbers. We will begin following SemVer once the project reaches `v2.0.0`__
Even though this project is above `v1.0.0`, we are rapidly changing and improving the API. This has caused versioning problems that aren't easily resolved because the project became popular very quickly (it was only started in March 2020).
We currently plan to start following SemVer once we reach the `v2.0.0` release, which will happen once the API starts to stabilize. Unfortunately, we don't currently have the timeline for this.
In accordance with Rust's policy on pre-`1.0.0` crates, we will try to keep breaking changes limited to minor version changes, but if things don't seem to be compiling after an upgrade, it is likely you'll need to dive into compiler errors to update some syntax that changed. Feel free to open an [issue](https://github.com/async-graphql/async-graphql/issues) if something seems weird!
## Features
* Fully supports async/await

View File

@ -15,7 +15,7 @@
```rust
struct Query;
#[Object]
#[GQLObject]
impl Query {
#[entity]
async fn find_user_by_id(&self, id: ID) -> User {

View File

@ -15,7 +15,7 @@ when querying multiple resolvers, the results of all cache control parameters wi
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.
```rust
#[Object(cache_control(max_age = 60))]
#[GQLObject(cache_control(max_age = 60))]
impl Query {
#[field(cache_control(max_age = 30))]
async fn value1(&self) -> i32 {

View File

@ -9,7 +9,7 @@ use async_graphql::*;
struct Query;
#[Object]
#[GQLObject]
impl Query {
async fn borrow_from_context_data<'ctx>(
&self,

View File

@ -10,7 +10,7 @@ use async_graphql::connection::*;
struct Query;
#[Object]
#[GQLObject]
impl Query {
#[field]
async fn numbers(&self,

View File

@ -11,7 +11,7 @@ use async_graphql::*;
struct StringNumber(i64);
#[Scalar]
#[GQLScalar]
impl ScalarType for StringNumber {
fn parse(value: Value) -> InputValueResult<Self> {
if let Value::String(value) = &value {

View File

@ -14,7 +14,7 @@ fn my_default() -> i32 {
30
}
#[Object]
#[GQLObject]
impl Query {
// The default value of the value parameter is 0, it will call i32::default()
fn test1(&self, #[arg(default)] value: i32) {}
@ -32,7 +32,8 @@ impl Query {
```rust
use async_graphql::*;
#[Interface(
#[derive(GQLInterface)]
#[graphql(
field(name = "test1", arg(name = "value", default)),
field(name = "test2", arg(name = "value", default = 10)),
field(name = "test3", arg(name = "value", default = "my_default()")),
@ -47,6 +48,7 @@ enum MyInterface {
```rust
use async_graphql::*;
#derive(GQLInputObject)
struct MyInputObject {
#[field(default)]
value1: i32,

View File

@ -17,7 +17,7 @@ struct MyObject {
value: i32,
}
#[Object]
#[GQLObject]
impl MyObject {
async fn value(&self) -> String {
self.value.to_string()

View File

@ -7,16 +7,17 @@ It's easy to define an `Enum`, here we have an example:
```rust
use async_graphql::*;
#[Enum(desc = "One of the films in the Star Wars Trilogy")]
/// One of the films in the Star Wars Trilogy
#[derive(GQLEnum, Copy, Clone, Eq, PartialEq)]
pub enum Episode {
#[item(desc = "Released in 1977.")]
/// Released in 1977.
NewHope,
#[item(desc = "Released in 1980.")]
/// Released in 1980.
Empire,
// rename to `AAA`
#[item(name="AAA", desc = "Released in 1983.")]
/// Released in 1983.
#[item(name="AAA")]
Jedi,
}
```

View File

@ -11,7 +11,7 @@ You can add optional `#[field]` attributes to add descriptions or rename the fie
```rust
use async_graphql::*;
#[InputObject]
#[derive(GQLInputObject)]
struct Coordinate {
latitude: f64,
@ -21,7 +21,7 @@ struct Coordinate {
struct Mutation;
#[Object]
#[GQLObject]
impl Mutation {
async fn users_at_location(&self, coordinate: Coordinate, radius: f64) -> Vec<User> {
// Writes coordination to database.

View File

@ -20,7 +20,7 @@ struct Circle {
radius: f32,
}
#[Object]
#[GQLObject]
impl Circle {
async fn area(&self) -> f32 {
std::f32::consts::PI * self.radius * self.radius
@ -40,7 +40,7 @@ struct Square {
width: f32,
}
#[Object]
#[GQLObject]
impl Square {
async fn area(&self) -> f32 {
self.width * self.width
@ -56,7 +56,8 @@ impl Square {
}
}
#[Interface(
#[derive(GQLInterface)]
#[graphql(
field(name = "area", type = "f32"),
field(name = "scale", type = "Shape", arg(name = "s", type = "f32"))
field(name = "short_description", method = "short_description", type = "String")

View File

@ -7,9 +7,12 @@ The example below defines an object `MyObject` which includes the fields `a` and
```rust
use async_graphql::*;
#[SimpleObject]
#[derive(GQLSimpleObject)]
struct MyObject {
/// Value a
a: i32,
#[field(desc = "Value b")]
b: i32,
#[field(skip)]

View File

@ -12,7 +12,7 @@ struct Circle {
radius: f32,
}
#[Object]
#[GQLObject]
impl Circle {
async fn area(&self) -> f32 {
std::f32::consts::PI * self.radius * self.radius
@ -27,7 +27,7 @@ struct Square {
width: f32,
}
#[Object]
#[GQLObject]
impl Square {
async fn area(&self) -> f32 {
self.width * self.width
@ -38,7 +38,7 @@ impl Square {
}
}
#[Union]
#[derive(GQLUnion)]
enum Shape {
Circle(Circle),
Square(Square),

View File

@ -16,7 +16,7 @@ use async_graphql::*;
struct Query;
#[Object]
#[GQLObject]
impl Query {
#[field]
async fn parse_with_extensions(&self, input: String) -> FieldResult<i32> {

View File

@ -14,7 +14,7 @@ use async_graphql::validators::{Email, MAC};
struct Query;
#[Object]
#[GQLObject]
impl Query {
async fn input(#[arg(validator(or(Email, MAC(colon = "false"))))] a: String) {
}
@ -29,7 +29,7 @@ use async_graphql::validators::{IntGreaterThan, IntLessThan, IntEqual};
struct Query;
#[Object]
#[GQLObject]
impl Query {
async fn input(#[validator(
or(

View File

@ -3,14 +3,14 @@
Usually we can create multiple implementations for the same type in Rust, but due to the limitation of procedural macros, we can not create multiple Object implementations for the same type. For example, the following code will fail to compile.
```rust
#[Object]
#[GQLObject]
impl Query {
async fn users(&self) -> Vec<User> {
todo!()
}
}
#[Object]
#[GQLObject]
impl Query {
async fn movies(&self) -> Vec<Movie> {
todo!()
@ -18,21 +18,21 @@ impl Query {
}
```
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.
Instead, the `#[derive(GQLMergedObject)]` 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 you're merging its own name.
**Tip:** Every `#[GQLObject]` 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.
```rust
#[Object]
#[GQLObject]
impl UserQuery {
async fn users(&self) -> Vec<User> {
todo!()
}
}
#[Object]
#[GQLObject]
impl MovieQuery {
async fn movies(&self) -> Vec<Movie> {
todo!()
@ -61,7 +61,7 @@ Example:
#[derive(Default)]
struct Subscription1;
#[Subscription]
#[GQLSubscription]
impl Subscription1 {
async fn events1(&self) -> impl Stream<Item = i32> {
futures::stream::iter(0..10)
@ -71,7 +71,7 @@ impl Subscription1 {
#[derive(Default)]
struct Subscription2;
#[Subscription]
#[GQLSubscription]
impl Subscription2 {
async fn events2(&self) -> impl Stream<Item = i32> {
futures::stream::iter(10..20)

View File

@ -9,7 +9,7 @@ use async_graphql::*;
struct Query;
#[Object]
#[GQLObject]
impl Query {
async fn user(&self, username: String) -> FieldResult<Option<User>> {
// Look up users from the database
@ -29,7 +29,7 @@ use async_graphql::*;
struct Mutation;
#[Object]
#[GQLObject]
impl Mutation {
async fn signup(&self, username: String, password: String) -> Result<bool> {
// User signup

View File

@ -23,7 +23,7 @@ use async_graphql::*;
struct Query;
#[Object]
#[GQLObject]
impl Query {
#[field(desc = "Returns the sum of a and b")]
async fn add(&self, a: i32, b: i32) -> i32 {

View File

@ -9,7 +9,7 @@ use async_graphql::*;
struct Subscription;
#[Subscription]
#[GQLSubscription]
impl Subscription {
async fn integers(&self, #[arg(default = "1")] step: i32) -> impl Stream<Item = i32> {
let mut value = 0;

View File

@ -17,7 +17,7 @@
```rust
struct Query;
#[Object]
#[GQLObject]
impl Query {
#[entity]
async fn find_user_by_id(&self, id: ID) -> User {

View File

@ -15,7 +15,7 @@
我们可以从查询结果`QueryResponse`中获取缓存控制合并结果,并且调用`CacheControl::value`来获取对应的HTTP头。
```rust
#[Object(cache_control(max_age = 60))]
#[GQLObject(cache_control(max_age = 60))]
impl Query {
#[field(cache_control(max_age = 30))]
async fn value1(&self) -> i32 {

View File

@ -9,7 +9,7 @@ use async_graphql::*;
struct Query;
#[Object]
#[GQLObject]
impl Query {
async fn borrow_from_context_data<'ctx>(
&self,

View File

@ -12,7 +12,7 @@ use async_graphql::connection::*;
struct Query;
#[Object]
#[GQLObject]
impl Query {
#[field]
async fn numbers(&self,

View File

@ -12,7 +12,7 @@ use async_graphql::*;
struct StringNumber(i64);
#[Scalar]
#[GQLScalar]
impl ScalarType for StringNumber {
fn parse(value: Value) -> InputValueResult<Self> {
if let Value::String(value) = &value {

View File

@ -13,7 +13,7 @@ fn my_default() -> i32 {
30
}
#[Object]
#[GQLObject]
impl Query {
// value参数的默认值为0它会调用i32::default()
fn test1(&self, #[arg(default)] value: i32) {}
@ -31,7 +31,8 @@ impl Query {
```rust
use async_graphql::*;
#[Interface(
#[derive(GQLInterface)]
#[graphql(
field(name = "test1", arg(name = "value", default)),
field(name = "test2", arg(name = "value", default = 10)),
field(name = "test3", arg(name = "value", default = "my_default()")),
@ -46,6 +47,7 @@ enum MyInterface {
```rust
use async_graphql::*;
#derive(GQLInputObject)
struct MyInputObject {
#[field(default)]
value1: i32,

View File

@ -15,7 +15,7 @@ struct MyObject {
value: i32,
}
#[Object]
#[GQLObject]
impl MyObject {
async fn value(&self) -> String {
self.value.to_string()

View File

@ -7,16 +7,17 @@
```rust
use async_graphql::*;
#[Enum(desc = "One of the films in the Star Wars Trilogy")]
/// One of the films in the Star Wars Trilogy
#[derive(GQLEnum, Copy, Clone, Eq, PartialEq)]
pub enum Episode {
#[item(desc = "Released in 1977.")]
/// Released in 1977.
NewHope,
#[item(desc = "Released in 1980.")]
/// Released in 1980.
Empire,
// rename to `AAA`
#[item(name="AAA", desc = "Released in 1983.")]
/// Released in 1983.
#[item(name="AAA")]
Jedi,
}
```

View File

@ -7,7 +7,7 @@
```rust
use async_graphql::*;
#[InputObject]
#[derive(GQLInputObject)]
struct Coordinate {
latitude: f64,
@ -17,7 +17,7 @@ struct Coordinate {
struct Mutation;
#[Object]
#[GQLObject]
impl Mutation {
async fn users_at_location(&self, coordinate: Coordinate, radius: f64) -> Vec<User> {
// 将坐标写入数据库

View File

@ -18,7 +18,7 @@ struct Circle {
radius: f32,
}
#[Object]
#[GQLObject]
impl Circle {
async fn area(&self) -> f32 {
std::f32::consts::PI * self.radius * self.radius
@ -38,7 +38,7 @@ struct Square {
width: f32,
}
#[Object]
#[GQLObject]
impl Square {
async fn area(&self) -> f32 {
self.width * self.width
@ -54,7 +54,8 @@ impl Square {
}
}
#[Interface(
#[derive(GQLInterface)]
#[graphql(
field(name = "area", type = "f32"),
field(name = "scale", type = "Shape", arg(name = "s", type = "f32"))
field(name = "short_description", method = "short_description", type = "String")

View File

@ -9,7 +9,7 @@
```rust
use async_graphql::*;
#[SimpleObject]
#[derive(GQLSimpleObject)]
struct MyObject {
/// Value a
a: i32,

View File

@ -11,7 +11,7 @@ struct Circle {
radius: f32,
}
#[Object]
#[GQLObject]
impl Circle {
async fn area(&self) -> f32 {
std::f32::consts::PI * self.radius * self.radius
@ -26,7 +26,7 @@ struct Square {
width: f32,
}
#[Object]
#[GQLObject]
impl Square {
async fn area(&self) -> f32 {
self.width * self.width
@ -37,7 +37,7 @@ impl Square {
}
}
#[Union]
#[derive(GQLUnion)]
enum Shape {
Circle(Circle),
Square(Square),

View File

@ -15,7 +15,7 @@ use async_graphql::*;
struct Query;
#[Object]
#[GQLObject]
impl Query {
#[field]
async fn parse_with_extensions(&self, input: String) -> FieldResult<i32> {

View File

@ -12,7 +12,7 @@ use async_graphql::validators::{Email, MAC};
struct Query;
#[Object]
#[GQLObject]
impl Query {
async fn input(#[arg(validator(or(Email, MAC(colon = "false"))))] a: String) {
}
@ -27,7 +27,7 @@ use async_graphql::validators::{IntGreaterThan, IntLessThan, IntEqual};
struct Query;
#[Object]
#[GQLObject]
impl Query {
async fn input(#[validator(
or(

View File

@ -7,13 +7,3 @@
## 为什么我要开发Async-graphql
我喜欢GraphQL和Rust之前我一直用`Juniper`它解决了我用Rust实现GraphQL服务器的问题但也有一些遗憾其中最重要的是它当时不支持async/await所以我决定做一个给自己用。
## 稳定性
__这个项目目前不遵循 [Semantic Versioning (SemVer)](https://semver.org/) ,并且可能会在任何版本号上发生不向前兼容的变化。一旦项目达到`v2.0.0`我们将确保每次更新符合SemVer的规范。__
尽管这个项目在`v1.0.0`之上但是我们正在快速迭代和改进API。这导致了版本控制问题这些问题不容易解决因为这个项目很快就流行起来(2020年3月才开始开发)。
我们目前计划在`v2.0.0`发布之后开始执行SemVer这将在API开始稳定之后发生。不幸的是我们目前还没有这方面的时间表。
根据Rust关于“ 1.0.0”之前的版本的政策,我们将尝试将不兼容的变化限制为次要版本更改,但如果升级后似乎未通过编译,则可能需要深入研究编译器错误以更新某些已更改的语法。如果有些奇怪,请随时打开 [issue](https://github.com/async-graphql/async-graphql/issues) 。

View File

@ -5,14 +5,14 @@
通常我们在Rust中可以为同一类型创建多个实现但由于过程宏的限制无法为同一个类型创建多个Object实现。例如下面的代码将无法通过编译。
```rust
#[Object]
#[GQLObject]
impl MyObject {
async fn field1(&self) -> i32 {
todo!()
}
}
#[Object]
#[GQLObject]
impl MyObject {
async fn field2(&self) -> i32 {
todo!()
@ -22,17 +22,17 @@ impl MyObject {
`#[derive(GQLMergedObject)]` 宏允许你合并多个独立的GQLObject为一个.
**提示:** 每个`#[Object]`需要一个唯一的名称,即使在一个`GQLMergedObject`内,所以确保每个对象有单独的名称。
**提示:** 每个`#[GQLObject]`需要一个唯一的名称,即使在一个`GQLMergedObject`内,所以确保每个对象有单独的名称。
```rust
#[Object]
#[GQLObject]
impl UserQuery {
async fn users(&self) -> Vec<User> {
todo!()
}
}
#[Object]
#[GQLObject]
impl MovieQuery {
async fn movies(&self) -> Vec<Movie> {
todo!()
@ -59,7 +59,7 @@ let schema = Schema::new(
#[derive(Default)]
struct Subscription1;
#[Subscription]
#[GQLSubscription]
impl Subscription1 {
async fn events1(&self) -> impl Stream<Item = i32> {
futures::stream::iter(0..10)
@ -69,7 +69,7 @@ impl Subscription1 {
#[derive(Default)]
struct Subscription2;
#[Subscription]
#[GQLSubscription]
impl Subscription2 {
async fn events2(&self) -> impl Stream<Item = i32> {
futures::stream::iter(10..20)

View File

@ -9,7 +9,7 @@ use async_graphql::*;
struct Query;
#[Object]
#[GQLObject]
impl Query {
async fn user(&self, username: String) -> FieldResult<Option<User>> {
// 在数据库中查找用户
@ -29,7 +29,7 @@ use async_graphql::*;
struct Mutation;
#[Object]
#[GQLObject]
impl Mutation {
async fn signup(&self, username: String, password: String) -> Result<bool> {
// 用户注册

View File

@ -23,7 +23,7 @@ use async_graphql::*;
struct Query;
#[Object]
#[GQLObject]
impl Query {
#[field(desc = "Returns the sum of a and b")]
async fn add(&self, a: i32, b: i32) -> i32 {

View File

@ -9,7 +9,7 @@ use async_graphql::*;
struct Subscription;
#[Subscription]
#[GQLSubscription]
impl Subscription {
async fn integers(&self, #[arg(default = "1")] step: i32) -> impl Stream<Item = i32> {
let mut value = 0;