Giter Club home page Giter Club logo

validator's Introduction

validator

Macros 1.1 custom derive to simplify struct validation inspired by marshmallow and Django validators.

The minimum supported version is Rust 1.42.

Installation:

[dependencies]
validator = { version = "0.18", features = ["derive"] }

A short example:

use serde::Deserialize;

// A trait that the Validate derive will impl
use validator::{Validate, ValidationError};

#[derive(Debug, Validate, Deserialize)]
struct SignupData {
    #[validate(email)]
    mail: String,
    #[validate(url)]
    site: String,
    #[validate(length(min = 1), custom(function = "validate_unique_username"))]
    #[serde(rename = "firstName")]
    first_name: String,
    #[validate(range(min = 18, max = 20))]
    age: u32,
    #[validate(range(exclusive_min = 0.0, max = 100.0))]
    height: f32,
}

fn validate_unique_username(username: &str) -> Result<(), ValidationError> {
    if username == "xXxShad0wxXx" {
        // the value of the username will automatically be added later
        return Err(ValidationError::new("terrible_username"));
    }

    Ok(())
}

match signup_data.validate() {
  Ok(_) => (),
  Err(e) => return e;
};

A validation on an Option<_> field will be executed on the contained type if the option is Some. The validate() method returns a Result<(), ValidationErrors>. In the case of an invalid result, the ValidationErrors instance includes a map of errors keyed against the struct's field names. Errors may be represented in three ways, as described by the ValidationErrorsKind enum:

#[derive(Debug, Serialize, Clone, PartialEq)]
#[serde(untagged)]
pub enum ValidationErrorsKind {
    Struct(Box<ValidationErrors>),
    List(BTreeMap<usize, Box<ValidationErrors>>),
    Field(Vec<ValidationError>),
}

In the simple example above, any errors would be of the Field(Vec<ValidationError>) type, where a single ValidationError has the following structure:

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct ValidationError {
  pub code: Cow<'static, str>,
  pub message: Option<Cow<'static, str>>,
  pub params: HashMap<Cow<'static, str>, Value>,
}

The value of the field will automatically be added to the params with a key of value.

Note that validator works in conjunction with serde: in the example we can see that the first_name field is renamed from/to firstName. Any error on that field will be in the firstName key of the hashmap, not first_name.

The other two ValidationErrorsKind types represent errors discovered in nested (vectors of) structs, as described in this example:

use serde::Deserialize;
// A trait that the Validate derive will impl
use validator::Validate;

#[derive(Debug, Validate, Deserialize)]
struct SignupData {
   #[validate(nested)]
   contact_details: ContactDetails,
   #[validate(nested)]
   preferences: Vec<Preference>,
   #[validate(required)]
   allow_cookies: Option<bool>,
}

#[derive(Debug, Validate, Deserialize)]
struct ContactDetails {
   #[validate(email)]
   mail: String,
}

#[derive(Debug, Validate, Deserialize)]
struct Preference {
   #[validate(length(min = 4))]
   name: String,
   value: bool,
}

match signup_data.validate() {
 Ok(_) => (),
 Err(e) => return e;
};

Here, the ContactDetails and Preference structs are nested within the parent SignupData struct. Because these child types also derive Validate, the fields where they appear can be tagged for inclusion in the parent struct's validation method.

Any errors found in a single nested struct (the contact_details field in this example) would be returned as a Struct(Box<ValidationErrors>) type in the parent's ValidationErrors result.

Any errors found in a vector of nested structs (the preferences field in this example) would be returned as a List(BTreeMap<usize, Box<ValidationErrors>>) type in the parent's ValidationErrors result, where the map is keyed on the index of invalid vector entries.

Usage

You will need to import the Validate trait.

The validator crate can also be used without the custom derive as it exposes all the validation functions and types.

Validators

The crate comes with some built-in validators and you can have several validators for a given field.

email

Tests whether the String is a valid email according to the HTML5 regex, which means it will mark some esoteric emails as invalid that won't be valid in a email input as well. This validator doesn't take any arguments: #[validate(email)].

url

Tests whether the String is a valid URL. This validator doesn't take any arguments: #[validate(url)];

length

Tests whether a String or a Vec match the length requirement given. length has 3 integer arguments:

  • min
  • max
  • equal

Using equal excludes the min or max and will result in a compilation error if they are found.

At least one argument is required with a maximum of 2 (having min and max at the same time).

Examples:

const MIN_CONST: u64 = 1;
const MAX_CONST: u64 = 10;

#[validate(length(min = 1, max = 10))]
#[validate(length(min = 1))]
#[validate(length(max = 10))]
#[validate(length(equal = 10))]
#[validate(length(min = "MIN_CONST", max = "MAX_CONST"))]

range

Tests whether a number is in the given range. range takes 1 or 2 arguments, and they can be normal (min and max) or exclusive (exclusive_min, exclusive_max, unreachable limits). These can be a number or a value path.

Examples:

const MAX_CONSTANT: i32 = 10;
const MIN_CONSTANT: i32 = 0;

#[validate(range(min = 1))]
#[validate(range(min = "MIN_CONSTANT"))]
#[validate(range(min = 1, max = 10))]
#[validate(range(min = 1.1, max = 10.8))]
#[validate(range(max = 10.8))]
#[validate(range(min = "MAX_CONSTANT"))]
#[validate(range(min = "crate::MAX_CONSTANT"))]
#[validate(range(exclusive_min = 0.0, max = 100.0))]
#[validate(range(exclusive_max = 10))]

must_match

Tests whether the 2 fields are equal. must_match takes 1 string argument. It will error if the field mentioned is missing or has a different type than the field the attribute is on.

Examples:

#[validate(must_match(other = "password2"))]

contains

Tests whether the string contains the substring given or if a key is present in a hashmap. contains takes 1 string argument.

Examples:

#[validate(contains = "gmail")]
#[validate(contains(pattern = "gmail"))]

does_not_contain

Pretty much the opposite of contains, provided just for ease-of-use. Tests whether a container does not contain the substring given if it's a string or if a key is NOT present in a hashmap. does_not_contain takes 1 string argument.

Examples:

#[validate(does_not_contain = "gmail")]
#[validate(does_not_contain(pattern = "gmail"))]

regex

Tests whether the string matches the regex given. regex takes 1 string argument: the path to a static Regex instance.

Examples:

use once_cell::sync::Lazy;

static RE_TWO_CHARS: Lazy<Regex> = Lazy::new(|| {
    Regex::new(r"[a-z]{2}$").unwrap()
});

#[validate(regex = *RE_TWO_CHARS)]
#[validate(regex(path = *RE_TWO_CHARS)]

credit_card

Test whether the string is a valid credit card number.

Examples:

#[validate(credit_card)]

custom

Calls one of your functions to perform a custom validation. The field reference will be given as a parameter to the function, which should return a Result<(), ValidationError>.

Examples:

#[validate(custom(function = "validate_something"))]
#[validate(custom(function = "::utils::validate_something"))]

You can also do your own validation by parsing the arguments from the validation function by setting context for struct. Applying custom validation using the use_context argument is accomplished by setting the use_context parameter. Defining the context parameter will implement the ValidateArgs trait with the corresponding function types like this:

use validator::{Validate, ValidateArgs, ValidationError};

fn validate(value: &str, context: &TestContext) -> Result<(), ValidationError> {
    [...]
}

struct TestContext(i64, i64);

#[derive(Debug, Validate)]
#[validate(context = TestContext)]
struct TestStruct {
    #[validate(custom(function = "validate", use_context))]
    value: String,
}

let test_struct: TestStruct = [...];
let test_context: TestContext = [...];
test_struct.validate_with_args(&test_context).is_ok();

It is also possible to pass references by using the lifetime 'v_a note that this lifetime should only be used for the function parameters like this:

fn validate_value(_: &str, arg: &mut Database) -> Result<(), ValidationError> {
    [...]
}

#[derive(Debug, Validate)] //   vvvv This is the lifetime for references
#[validate(context = "Database<'v_a>", mutable)]
struct TestStruct {
    #[validate(custom(function = "validate_value", use_context))]
    value: String,
}

let mut database: Database = [...];
let test_struct: TestStruct = [...];
test_struct.validate_with_args(&mut database).is_ok();

Custom validation with arguments doesn't work on nested validation. See validator_derive_tests/tests/custom.rs and validator_derive_tests/tests/custom_args.rs for more examples.

nested

Performs validation on a field with a type that also implements the Validate trait (or a vector of such types).

Examples:

#[validate]

non_control_character

Tests whether the String has any utf-8 control characters, fails validation if it does. To use this validator, you must enable the unic feature for the validator crate. This validator doesn't take any arguments: #[validate(non_control_character)];

required

Tests whether the Option<T> field is Some;

Struct level validation

Often, some error validation can only be applied when looking at the full struct, here's how it works here:

#[derive(Debug, Validate, Deserialize)]
#[validate(schema(function = "validate_category", skip_on_field_errors = false))]
struct CategoryData {
    category: String,
    name: String,
}

The function mentioned should return a Result<(), ValidationError> and will be called after validation is done for all fields.

The skip_on_field_errors defaults to true if not present and will ensure that the function is not called if an error happened while validating the struct fields.

Any error on the struct level validation will appear in the key __all__ of the hashmap of errors.

Message and code

Each validator can take 2 optional arguments in addition to their own arguments:

  • message: a message to go with the error, for example if you want to do i18n
  • code: each validator has a default error code (for example the regex validator code is regex) but it can be overridden if necessary, mainly needed for the custom validator

Note that these arguments can't be applied to nested validation calls with #[validate].

For example, the following attributes all work:

// code attribute
#[validate(email(code = "code_str"))]
#[validate(credit_card(code = "code_str"))]
#[validate(length(min = 5, max = 10, code = "code_str"))]

#[validate(regex(path = *static_regex, code = "code_str"))]
#[validate(custom(function = "custom_fn", code = "code_str"))]
#[validate(contains(pattern = "pattern_str", code = "code_str"))]
#[validate(does_not_contain(pattern = "pattern_str", code = "code_str"))]
#[validate(must_match(other = "match_value", code = "code_str"))]

// message attribute
#[validate(url(message = "message_str"))]
#[validate(length(min = 5, max = 10, message = "message_str"))]

#[validate(regex(path = *static_regex, message = "message_str"))]
#[validate(custom(function = "custom_fn", message = "message_str"))]
#[validate(contains(pattern = "pattern_str", message = "message_str"))]
#[validate(does_not_contain(pattern = "pattern_str", message = "message_str"))]
#[validate(must_match(other = "match_value", message = "message_str"))]

// both attributes
#[validate(url(message = "message", code = "code_str"))]
#[validate(email(code = "code_str", message = "message"))]
#[validate(custom(function = "custom_fn", code = "code_str", message = "message_str"))]

validator's People

Contributors

babalolajnr avatar barzamin avatar buinauskas avatar dxist avatar dyedgreen avatar eijebong avatar eld avatar initerworker avatar keats avatar kyrias avatar nopenoshishi avatar nu11ptr avatar pepsighan avatar pintariching avatar pjenvey avatar rakshith-ravi avatar rosslannen avatar shadoysv avatar simonsparks avatar teddywing avatar theduke avatar tomcur avatar tomhoule avatar tuetuopay avatar valeriansaliou avatar voidxnull avatar wolthom avatar xfrednet avatar yannickleroux avatar yerke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

validator's Issues

validation for CLI

Would be nice if there where some validators to usual command line input. The most basic ones would be to check if a file or directory exist or a glob pattern matches anything. Maybe also some validators to do something with networking (url's). Don't know what else would be useful for cli

attr_literals won't be stable in 1.15

From the readme:

It currently only works on nightly but should work on stable in Rust 1.15.

This is not true right? The proc_macro feature will be stabilized but this library currently relies heavily on attr_literals as well which I have not seen plans to stabilize so far. The tracking issue is rust-lang/rust#34981.

Validating `Cow<'a, str>`

It is often useful to represent a struct's string fields with the Cow<'a, str> type to handle borrowing efficiently. The pattern is well described in the From &str to Cow article by Jow Wilm.

It would be equally useful if the validators in this library that operate on string types also supported fields declared as Cow<'a, str>.

the trait bound `std::borrow::Cow<'_, str>: std::convert::From<&std::string::String>` is not satisfied

In stable Rust, trying this example:

#[derive(Debug, Validate, Deserialize)]
struct SignupData {
    #[validate(email)]
    email: String,
}

I get this error:

  --> src/main.rs:11:17
   |
11 | #[derive(Debug, Validate, Deserialize)]
   |                 ^^^^^^^^ the trait `std::convert::From<&std::string::String>` is not implemented for `std::borrow::Cow<'_, str>`
   |
   = help: the following implementations were found:
             <std::borrow::Cow<'a, std::path::Path> as std::convert::From<std::path::PathBuf>>
             <std::borrow::Cow<'a, std::path::Path> as std::convert::From<&'a std::path::Path>>
             <std::borrow::Cow<'a, str> as std::convert::From<&'a str>>
             <std::borrow::Cow<'a, [T]> as std::convert::From<&'a [T]>>
           and 4 others
   = note: required because of the requirements on the impl of `std::convert::Into<std::borrow::Cow<'_, str>>` for `&std::string::String`
   = note: required by `validator::validate_email`

Thanks

Could ValidationErrors::field_errors() take &self instead of self?

Hey, I was wondering what the reason for making field_errors() take self was?

I have some code that needs to call it on a borrowed ValidationErrors instance, and have resorted to doing an explicit clone() beforehand. But it seems like it would work just as well if it took &self instead. Am I missing something / would you consider a change to the API?

Range validator cannot be used on Optional fields

#[macro_use]
extern crate validator_derive;
extern crate validator;

use validator::Validate;

#[derive(Validate)]
pub struct Foo {
	#[validate(length(min = "1"))]
	pub name: String,
	#[validate(range(min = 0, max = 120))]
	pub age: Option<i32>,
}

yields

Invalid attribute #[validate] on field age: Validator range can only be used on number types but found Option<i32>

Using Validator 0.4.0

Pass validation message into validate macro

I was wondering if it was at all possible to provide a message into the validate macro that could be used when returning a response back to the caller. The caller then could just essentially present the message to the user without needing to "know" the error code. Something like this maybe:

#[derive(Validate)]
pub struct Something {
    #[validate(length(min = "3", error="Must be at least 3 characters long"))]
    pub name: String
}

I don't know enough about macros 1.1 to know if this is even feasible but it would keep a user friendly error bundled with the validate declaration.

Plausible or not?

Make `must_match` work with Option?

Not sure if it even make sense to be honest, I had

pub fn validate_must_match<T>(a: T, b: T) -> bool
    where
        I: Eq,
        T: Into<Option<I>>,
        T2: Into<Option<I>>,
{
    let a = a.into();
    let b  = b.into();
    if a.is_none() && b.is_none() {
        return true;
    }
    if !(a.is_some() && b.is_some()) {
        return false;
    }
    a == b
}

before removing it

Validating `Option::is_some`

I haven't used your library yet, but it looks nice—

However, one of the primary validations I would want to perform on my structs would be Option::is_some, basically to check whether a builder-style struct is in a valid state.

It looks like the custom validator won't work here, since that is only run on the inner value in the Option::Some case.

I understand why you've designed it so validators are only run on options if Option::is_some, but it would be nice to have either an is_some validator or a custom validator that runs on the raw value.

Use range syntax for length validator?

From #73

// for length from 5 to 10 (10 is excluded)
#[validate(length(5..10))]   

// for length from 5 to 10 (10 is included)
#[validate(length(5..=10))]

// for length equal to 5
#[validate(length(5))]

To replace min/max/equal.

Thoughts?

How to pass args to custom validators?

I want to have a validator that works like length but uses the byte length of a string (or rather, the length after converting utf8 to cp852).

How can I pass the len arg to that custom validation function?

Add struct level validation

Sometimes fields can ok individually but might be invalid when looking at the whole thing, for example 2 fields are optional but at least one of them has to be there

Allowing a custom function on the struct itself is necessary

Bug: Nested type, where inner type field is an Option<InnerType>, and has a value, is failing to validate

In the following example, an incorrect postal_cd is provided. I expected validate() to raise a ValidationError but instead returned Ok(()). Is this a bug?

extern crate validator;
extern crate failure;
#[macro_use] extern crate validator_derive;

use validator::{Validate, ValidationError};
use failure::Error;

#[derive(Validate)]
pub struct Address {
    pub street: String,
    #[validate(length(min = "1", max = "5"))]
    pub postal_cd: String
}

#[derive(Validate)]
pub struct PartyInfo {
    #[validate(length(min = "1", max = "5"))]
    pub first_name: Option<String>,
    #[validate(length(min = "1", max = "10"))]
    pub last_name: Option<String>,
    pub address: Option<Address>
}

fn main() -> Result<(), Error>{
    let addr = Address {street: "123 main st".to_string(),
                        postal_cd: "0703000000000000".to_string()};
        let party = PartyInfo {first_name: Some("Darin".to_string()),
                           last_name: Some("Gordon".to_string()),
                           address: Some(addr)};
        let check = party.validate()?;
    println!("check is: {:?}", check);

    Ok(())
}

string length validation not working as expected

Why does this work? I am using validator = "0.6.3" and validator_derive = "0.6.5", rustc stable 1.25

#[derive(Validate)]
struct Something {
    field_a: String,
    #[validate(length(min = "1", max = "10"))]
    field_b: String
}

fn main() {
    let something = Something {field_a: "hello".to_string(),
                               field_b: "helloooooooooooooooooooooooooooo".to_string()};
}

Support using validators without attr_literals feature

Obvious follow-up to #4 I guess.

I know this is more user-friendly: #[validate(range(min = 18, max = 20))]

But would it be possible to support this as well? #[validate(range(min = "18", max = "20"))]

And similar for the other validators. This would allow validators to be used on stable Rust 1.15.

It looks like this may be as simple as just extending the lit_to_int and lit_to_float functions to handle string literals.

Regex validator

Need to figure out how to make it without having to compile the regex everytime.

A few possible choices:

  • pass an ident to the regex(ident=X) attribute and expect that to be a Regex object
  • use lazy_static inside the generated impl but that requires the end user adding lazy_static manually to their dependencies (afaik)

Use `Cow<'static, str>` instead of `String`

Hi!

There is no point to allocate memory each time for a String value, much frequently we will need an &'static str value and only in rare cases we will need to allocate String for custom values.

for validate:

Result<(), HashMap<String, Vec<String>>>

=>

Result<(), HashMap<Cow<'static, str>, Vec<Cow<'static, str>>>>

or even

Result<(), HashMap<&'static str, Vec<Cow<'static, str>>>>

for custom validation functions respectively:

Option<Cow<'static, str>

Error Localization?

When using a range or length validator I want to display the min and max args in the error but in a different language, how to do that?

Suggestion: Actix integration that validates directly from the request? (behind a feature flag of course)

#[derive(Deserialize, Validate)]
pub struct Foo {
  #[validate(range(min = "10", max = "100"))]
  bar: u32,
}

fn index(body: Validated<Json<Foo>>) {  ... }

Validated would be a pub struct Validated<T>(T) wrapper struct that implements actix_web::FromRequest and returns a 422 on validation errors with a nice response body describing errors.


If this is something you feel should be included I'd love to contribute a PR here.

function to receive validation rules

It is not an issue, maybe a feature request

But how can I get validation rules, to use them in frontend (js) ?
Any format of validation rules will suit me.

And if there is a custom validation - I just would like to know that field have custom validation also and that'it

Forward thank you for any your reply

Validation of nested structs?

Let's say I'm deserializing to a parent struct whose fields are other structs, which implement Validate. I hoped that if I called validate() on the parent, it would automatically call validate() on its nested structs. But this code prints out "validated!", even though Bar is invalid:

#[macro_use]
extern crate serde_derive;
extern crate toml;
#[macro_use]
extern crate validator_derive;
extern crate validator;

use validator::{Validate};

#[derive(Deserialize, Debug, Validate)]
struct Foo {
    bar: Bar,
}

#[derive(Deserialize, Debug, Validate)]
struct Bar {
    #[validate(range(min = "0", max = "9"))]
    y: i32
}

fn main() {
    let foo: Foo = toml::from_str(r#"
    [bar]
    y = -1
    "#).unwrap();

    match foo.validate() {
        Ok(_) => println!("validated!"),
        Err(e) => println!("{:?}", e),
    };
}

I can't figure out a good way to explicitly call validate() on the nested struct, either. I tried adding a #[validate(custom("Bar::validate"))] attribute to the bar field, but that resulted in error: proc-macro derive panicked.

Is there any better way to validate nested structs than to implement my own method for Foo that manually calls validate() on every field?

Serializable validations

It would be nice if the Validate trait could provide access to the validations used on a struct. (Ex, a hashmap of Vecs of Validator.)

Give the Validator enum Serialize and now you can serialize it to json and pass it to a front end app to share validations. :D

Port to macros 1.1

Thanks for the awesome work, love this crate.

With macros 1.1 now becoming stable, do you have any plans to port this over?

That would allow use on stable!

serde: support for validation during deserialization

This is basically cross-linking the whole discussion at serde-rs/serde#642.

It would be nice to have this crate and serde team-up to provide some way for performing a validation pass as the last step of deserialization. For simple average-case scenarios, I'd like to avoid explicitely calling validate() on a struct that has just been deserialized by serde.

The usecase for this is to automatically ensure that a struct is guaranteed to be either valid right after deserialization or to fail it, in order to avoid invalid states between deserialization and validation (or worse, missing validation at some call sites).

Won't compile on Stable Rustc 1.20.0 nor 1.21.0 because of card_validate

Compiling card-validate v2.1.2
error[E0554]: #[feature] may not be used on the stable release channel
 --> /Users/greg/.cargo/registry/src/github.com-1ecc6299db9ec823/card-validate-2.1.2/src/lib.rs:4:1
  |
4 | #![feature(inclusive_range, range_contains)]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Looks like one of validator's dependencies, card_validate, cannot compile on Stable Rust. What's the best way to fix this?

Error and Display are not implemented for validator::ValidationErrors

Which makes it quite inconvenient and unintuitive to use the result of Validate::validate with the ? operator. While a trivial implementation of std::error:Error would probably suffice, I'm not sure about the implementation of std::fmt::Display.

There also seems to be a mistake in README.md:

let errors = signup_data.validate()?;

According to

fn validate(&self) -> Result<(), ValidationErrors>;

validate doesn't return anything.

Does not work on Option<Option<T>>

Though validation works on Option<T>, it would be beneficial if the same logic would work on Option<Option<T>>.
To communicate with the JS world with null, undefined & T, I need to use Option<Option<T>>. And to validate it, currently I am using custom validation.
So, this is a feature request to make it built-in.

Add a `contains` validator

  • string: pretty obvious
  • hashmap: whether it contains the key given (limit to String key?)
  • vec: whether it contains the value given -> seems too much trouble for something NOT very useful (it would need to take a path to a variable, which sucks if you want to check for an integer or something similar)

Define a format for errors and/or allow user defined error messages

Right now it only returns the error code for the validation that failed, which is enough for me as I usually have control of both frontend and backend and just want to know which bit failed on which field.

However, having some more verbose error or user-defined ones (or both) would be welcome.
For example when sending error message to a third party doing an API calls or if you don't control the frontend and need to send all the info (args used for the validator) to it.

A few things to consider:

Serialize validators

Change the error type of validate from Result<(), HashMap<String, Vec<String>>> to Result<(), HashMap<String, Vec<Validator>>> and have Validator manually (so we can add their name) implement Serialize from Serde.

Pros
That's the easy option since this way we will get the name of the validator and all its args easily
Cons
Doesn't really work if we want custom error messages

Custom message

Add an optional error_msg field to every single validator that will be sent with the error code. Sending only the error message makes it less flexible wrt if the frontend wants to change it, so we should it still have both error code and error. Error type will be Result<(), HashMap<String, Vec<(String, Option<String>)>>>

Default error messages

A neat way to do that would be to impl a function on Validator that returns a default error message. I would ignore i18n in default error messages as I don't think it will provide a good end user interface since end users will end up with errors like "Bank account number must match [0-9]{7}" or something like that that I got today with Transferwise.
Proper error messages should be built by using the serialized validators in the frontend or just overwritten in the backend directly. There are also too many format for i18n and afaik not library for it in Rust yet.

The user could iterate on the errors hashmap or we could even impl a function on the hashmap directly so the user can do something like if they just want a hashmap with error messages:

match signup_data.validate() {
   Ok(()) => (),
   Err(e) => return e.get_error_messages()
};

which could be turned into a validate_or_error_messages! macro easily

If that approach works, it could be extended to transform errors into i18n objects potentially

Current thoughts

I like the idea of serializing validators and having default error messages if wanted but I'm not sure where the custom error messages fit in that system. Ideally we'd have String | Validator as type for the value of hashmap but that's not possible in Rust. Another option is (Validator, Option<String>).
The main issue would be what to do with the custom validator since you can have multiple kind of errors and how to work with serialization errors if we decide to let validator handle those (for consistent errors)

Option<String> doesn't work

Why doesn't Option<String> work? Shouldn't it work in v0.6.3?

image

#[validate(regex = "RE_TIME")]
automatic_closing_time: Option<String>,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.