2020-04-15 03:15:30 +00:00
# Input value validators
2020-05-09 21:39:04 +00:00
2021-10-08 16:49:02 +00:00
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.
2020-05-09 21:39:04 +00:00
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:
```rust
use async_graphql::*;
use async_graphql::validators::{Email, MAC};
struct Query;
2020-09-18 00:52:13 +00:00
#[Object]
2020-05-09 21:39:04 +00:00
impl Query {
2020-09-28 09:44:00 +00:00
async fn input(#[graphql(validator(or(Email, MAC(colon = "false"))))] a: String) {
2020-05-09 21:39:04 +00:00
}
}
```
The following example verifies that the `i32` parameter `a` is greater than 10 and less than 100, or else equal to 0:
```rust
2021-07-20 07:16:34 +00:00
use async_graphql::*;
2020-05-09 21:39:04 +00:00
use async_graphql::validators::{IntGreaterThan, IntLessThan, IntEqual};
struct Query;
2020-09-18 00:52:13 +00:00
#[Object]
2020-05-09 21:39:04 +00:00
impl Query {
2021-05-19 02:51:50 +00:00
async fn input(#[graphql(validator(
2020-05-09 21:39:04 +00:00
or(
and(IntGreaterThan(value = "10"), IntLessThan(value = "100")),
IntEqual(value = "0")
2021-05-19 02:51:50 +00:00
)))] a: String) {
2021-07-20 07:16:34 +00:00
}
}
```
## Validate the elements of the list.
You can use the `list` operator to indicate that the internal validator is used for all elements in a list:
```rust
use async_graphql::*;
use async_graphql::validators::Email;
struct Query;
#[Object]
impl Query {
async fn input(#[graphql(validator(list(Email)))] emails: Vec< String > ) {
2020-05-09 21:39:04 +00:00
}
}
```
## Custom validator
Here is an example of a custom validator:
```rust
struct MustBeZero {}
2020-08-03 12:43:15 +00:00
impl InputValueValidator for MustBeZero {
2020-07-30 01:43:51 +00:00
fn is_valid(& self, value: & Value) -> Result< (), String> {
2020-05-09 21:39:04 +00:00
if let Value::Int(n) = value {
if n.as_i64().unwrap() != 0 {
// Validation failed
2020-07-30 01:43:51 +00:00
Err(format!(
2020-05-09 21:39:04 +00:00
"the value is {}, but must be zero",
n.as_i64().unwrap(),
))
} else {
// Validation succeeded
2020-07-30 01:43:51 +00:00
Ok(())
2020-05-09 21:39:04 +00:00
}
} else {
// If the type does not match we can return None and built-in validations
// will pick up on the error
2020-07-30 01:43:51 +00:00
Ok(())
2020-05-09 21:39:04 +00:00
}
}
}
```
2021-09-11 16:31:43 +00:00
Here is an example of a custom validator with extensions (return `async_graphql::Error` ):
```rust
pub struct Email;
impl InputValueValidator for Email {
fn is_valid_with_extensions(& self, value: & Value) -> Result< (), Error> {
if let Value::String(s) = value {
if & s.to_lowercase() != s {
return Err(Error::new("Validation Error").extend_with(|_, e| {
e.set("key", "email_must_lowercase")
}));
}
if !validate_non_control_character(s) {
return Err(Error::new("Validation Error").extend_with(|_, e| {
e.set("key", "email_must_no_non_control_character")
}));
}
if !validate_email(s) {
return Err(Error::new("Validation Error").extend_with(|_, e| {
e.set("key", "invalid_email_format")
}));
}
}
Ok(())
}
}
```