somehowchris / rocket-validation

A guard to validate data received by rocket via validator
16 stars 4 forks source link

Its possible get the ValidationErrors in request guard #20

Closed allanHaroldMarques closed 1 year ago

allanHaroldMarques commented 1 year ago

I implemented the validation as follows:

use serde::{Serialize, Deserialize};

use regex::Regex;
use rocket_validation::{Validate};

use lazy_static::lazy_static;

#[derive(Debug, Serialize, Deserialize, Validate)]
#[serde(crate = "rocket::serde")]
pub struct CatOnwerCreate {
    #[validate(regex(path = "RE_TWO_CHARS", message = "error message here"))]
    cat_gender: String,
}

lazy_static! {
    static ref RE_TWO_CHARS: Regex = Regex::new("^(apple|banana)$").unwrap();
}

In the route:

#[post("/cat-owner", format = "application/json", data = "<cat_onwer>")]
pub fn create_cat_owner(cat_onwer: Validated<Json<CatOnwerCreate>>) -> Json<CatOnwerCreate> {
    cat_onwer.into_inner()
}

works well. In the stdout(log) it says:

Data guard `Validated < Json < CatOnwerCreate > >` failed: Ok(ValidationErrors({"cat_gender": Field([ValidationError { code: "regex", message: Some("error message here"), params: {"value": String("lala")} }])}))

I have a catch(400) that catches the validator error like this::

#[catch(400)]
pub fn bad_request(req: &Request<'_>) -> ApiError {
    ApiError { code: StatusCode::BadRequest, message:"aaa".to_string() }
}

Is there any way for me to get the error message in this cacth through the (req) Request ?

somehowchris commented 1 year ago

If you need to get the error message inside your route handle you could simply use Result<Validated<Json<CatOwnerCreate>>> which is explained as an example inside the rocket docs

Else if you would like to catch all errors, regardless of the route, you could use the same implementation as the validation_catcher function of this crate, the CachedValidationErrors type is already public.

allanHaroldMarques commented 1 year ago

I was able to do, like this:

#[catch(400)]
pub async fn bad_request(req: &Request<'_>) -> ApiError {
    let validation_errors = req.local_cache(|| CachedValidationErrors(None)).0.as_ref();
    let mut message = "Something goes wrong!".to_string();

    if validation_errors.is_some() {
        message.clear();

        let erros = validation_errors.unwrap().field_errors();

        for (_,val) in erros.iter() {
            for (error) in val.iter() {
                message.push_str(error.message.as_ref().unwrap());
            }
        }
    }

    ApiError { code: StatusCode::BadRequest, message: message }
}

Thank you!