Merge pull request #64 from DataCorrupted/master
Translate type system almost done with some TODO.
This commit is contained in:
commit
9902b3c339
|
@ -1 +1,21 @@
|
|||
# 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 following example shows how to borrow data in `Context`.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn borrow_from_context_data<'ctx'>(
|
||||
&self,
|
||||
ctx: &'ctx Context<'_>
|
||||
) -> &'ctx String {
|
||||
ctx.data::<String>
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1 +1,34 @@
|
|||
# Object
|
||||
|
||||
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.**
|
||||
|
||||
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.
|
||||
|
||||
<!--TODO: 全局类型的数据?-->
|
||||
When querying a database, you may need a global data base connection pool, you can use `Schema::data` to attach a global data when creating Schema, the following `value_from_db` function showed how to retrive a database connection from `Context`.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
||||
struct MyObject {
|
||||
value: i32,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl MyObject {
|
||||
async fn value(&self) -> String {
|
||||
self.value.to_string()
|
||||
}
|
||||
|
||||
async fn value_from_db(
|
||||
&self,
|
||||
ctx: &Context<'_'>,
|
||||
#[arg(desc = "Id of object")] id: i64
|
||||
) -> FieldResult<String> {
|
||||
let conn = ctx.data::<DbPool>().take();
|
||||
Ok(conn.query_something(id)?.name)
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1 +1,22 @@
|
|||
# Enum
|
||||
|
||||
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.**
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
||||
#[Enum(desc = "One of the films in the Star Wars Trilogy")]
|
||||
pub enum Episode {
|
||||
#[item(desc = "Released in 1977.")]
|
||||
NewHope,
|
||||
|
||||
#[item(desc = "Released in 1980.")]
|
||||
Empire,
|
||||
|
||||
// rename to `AAA`
|
||||
#[item(name="AAA", desc = "Released in 1983.")]
|
||||
Jedi,
|
||||
}
|
||||
```
|
|
@ -1 +1,31 @@
|
|||
# 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.
|
||||
|
||||
`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.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
||||
#[InputObject]
|
||||
struct Coordinate {
|
||||
latitude: f64,
|
||||
|
||||
#[field(desc = "...")]
|
||||
longitude: f64
|
||||
}
|
||||
|
||||
struct Mutation;
|
||||
|
||||
#[Object]
|
||||
impl Mutation {
|
||||
async fn users_at_location(&self, coordinate: Coordinate, radius: f64) -> Vec<User> {
|
||||
// Writes coordination to database.
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1 +1,48 @@
|
|||
# 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` implemented auto conversion from `Object` to `Interface`, you only need to call `Into::into`.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
||||
struct Circle {
|
||||
radius: f32,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl Circle {
|
||||
async fn area(&self) -> f32 {
|
||||
std::f32::consts::PI * self.radius * self.radius
|
||||
}
|
||||
|
||||
async fn scale(&self, s: f32) -> Shape {
|
||||
Circle { radius: self.radius * s }.into()
|
||||
}
|
||||
}
|
||||
|
||||
struct Square {
|
||||
width: f32,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl Square {
|
||||
async fn area(&self) -> f32 {
|
||||
self.width * self.width
|
||||
}
|
||||
|
||||
async fn scale(&self, s: f32) -> Shape {
|
||||
Square { width: self.width * s }.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[Interface(
|
||||
field(name = "area", type = "f32"),
|
||||
field(name = "scale", type = "Shape", arg(name = "s", type = "f32"))
|
||||
)]
|
||||
struct Shape(Circle, Square);
|
||||
```
|
|
@ -1 +1,18 @@
|
|||
# SimpleObject
|
||||
|
||||
`SimpleObject` directly map all field of a struct to GraphQL object, you cannot define a Resolve 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)]`
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
||||
#[SimpleObject]
|
||||
struct MyObject {
|
||||
a: i32,
|
||||
b: i32,
|
||||
|
||||
#[field(skip)]
|
||||
c: i32,
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1 +1,44 @@
|
|||
# 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 following example modified the definition of `Interface` a little bit and removed fields.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
||||
struct Circle {
|
||||
radius: f32,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl Circle {
|
||||
async fn area(&self) -> f32 {
|
||||
std::f32::consts::PI * self.radius * self.radius
|
||||
}
|
||||
|
||||
async fn scale(&self, s: f32) -> Shape {
|
||||
Circle { radius: self.radius * s }.into()
|
||||
}
|
||||
}
|
||||
|
||||
struct Square {
|
||||
width: f32,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl Square {
|
||||
async fn area(&self) -> f32 {
|
||||
self.width * self.width
|
||||
}
|
||||
|
||||
async fn scale(&self, s: f32) -> Shape {
|
||||
Square { width: self.width * s }.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[Union]
|
||||
struct Shape(Circle, Square);
|
||||
```
|
|
@ -1 +1,28 @@
|
|||
# Error handling
|
||||
|
||||
Resolve can return a `FieldResult`, following is the definition:
|
||||
|
||||
```rust
|
||||
type FieldResult<T> = std::result::Result<T, FieldError>;
|
||||
```
|
||||
|
||||
<!--TODO: 扩展标准的错误输出? -->
|
||||
Any `Error` can be converted to `FieldError` and you can extend error message.
|
||||
|
||||
Following example shows how to parse an input string to integer. When parsing failed, it would return error and attach error message.
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
#[field]
|
||||
async fn parse_with_extensions(&self, input: String) -> FieldResult<i32> {
|
||||
Ok("234a"
|
||||
.parse()
|
||||
.map_err(|err| err.extend_with(|_| json!({"code": 400})))?)
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1 +1,3 @@
|
|||
# Type System
|
||||
|
||||
`Async-graphql` implemented conversion from GraphQL Object to Rust struct, and it's easy to use.
|
Loading…
Reference in New Issue
Block a user