async-graphql/docs/en/src/field_guard.md

84 lines
1.7 KiB
Markdown
Raw Normal View History

2020-10-06 09:16:51 +00:00
# Field Guard
2021-11-16 06:51:20 +00:00
You can define a `guard` for the fields of `Object`, `SimpleObject`, `ComplexObject` and `Subscription`, it will be executed before calling the resolver function, and an error will be returned if it fails.
2020-10-06 09:16:51 +00:00
```rust
#[derive(Eq, PartialEq, Copy, Clone)]
enum Role {
Admin,
Guest,
}
struct RoleGuard {
role: Role,
}
2021-11-16 06:51:20 +00:00
impl RoleGuard {
fn new(role: Role) -> Self {
Self { role }
}
}
2020-10-06 09:16:51 +00:00
#[async_trait::async_trait]
impl Guard for RoleGuard {
async fn check(&self, ctx: &Context<'_>) -> Result<()> {
if ctx.data_opt::<Role>() == Some(&self.role) {
Ok(())
} else {
Err("Forbidden".into())
}
}
}
```
2021-11-16 06:51:20 +00:00
Use it with the `guard` attribute:
2020-10-06 09:16:51 +00:00
```rust
#[derive(SimpleObject)]
struct Query {
2021-11-16 06:51:20 +00:00
/// Only allow Admin
#[graphql(guard = "RoleGuard::new(Role::Admin)")]
value1: i32,
/// Allow Admin or Guest
#[graphql(guard = "RoleGuard::new(Role::Admin).or(RoleGuard::new(Role::Guest))")]
2020-10-06 09:16:51 +00:00
value2: i32,
}
```
2021-11-16 06:51:20 +00:00
## Use parameter value
Sometimes guards need to use field parameters, you need to pass the parameter value when creating the guard like this:
```rust
struct EqGuard {
expect: i32,
actual: i32,
}
impl EqGuard {
fn new(expect: i32, actual: i32) -> Self {
Self { expect, actual }
}
}
#[async_trait::async_trait]
impl Guard for EqGuard {
async fn check(&self, _ctx: &Context<'_>) -> Result<()> {
if self.expect != self.actual {
Err("Forbidden".into())
} else {
Ok(())
}
}
}
struct Query;
#[Object]
impl Query {
#[graphql(guard = "EqGuard::new(100, value)")]
async fn get(&self, value: i32) -> i32 {
value
}
}
```