GithubHelp home page GithubHelp logo

innoave / valid Goto Github PK

View Code? Open in Web Editor NEW
14.0 2.0 0.0 125 KB

composable validation functions for custom types

License: Other

Rust 100.00%
validation composable composition custom-types constraints validate business-rules

valid's Introduction

valid

Latest Release Documentation License Build Status Test Coverage Rustc Version 1.39+

Let the business logic only accept valid values!

  • Validate custom types by composing primitive validation functions.

  • Use one common API for validating all kind of business rules including aspects of the application state.

  • One common error type for all kind of constraint validations. It is designed to help with error messages that are meaningful to the user of an application.

valid is a validation library for the Rust language. It let us write validation functions for our custom types through composition of available validators. Any custom written validation function again can be used to build validations for even more complex types.

The valid crate defines the types and traits to implement validation functions and use them to validate our values. Additionally, it defines primitive constraints.

Most primitive constraints validate one property of the validated type. E.g. the Length constraint validates the length property of strings, container types or slices. If the constraint property is not covered by a trait of the std-lib, a related trait is defined, which we call a property trait.

The builtin constraints are implemented for generic types T that implement the related property trait.

One goal of valid is to provide one common API that can be used to validate all kind of business rules. Constraints are grouped into one of 3 categories:

  1. field level constraint, e.g. only a range of values is allowed
  2. the relation of 2 fields, e.g. 2 password fields must match or 2 fields must define a range
  3. business rules that verify some aspect of the application state, e.g. a username must be unique

Any violation of constraints are returned in one common error type, regardless of the category of the business rule that defines the constraint.

One principle for the core functionality of this crate is to have no dependencies other than the std-lib. Support for types of 3rd party crates such as bigdecimal and chrono are implemented as optional crate features. So you can pick and choose which types you need in your application and which dependencies you will have in your project.

Features

  • Common validation API for validating constraints on field values, constraints on related fields and constraints on application state
  • Definition of primitive constraints, such as Length, CharCount, Bound and MustMatch
  • Generic implementations of the validation function for the provided constraints
  • Composition of validation functions to implement validation for complex types
  • One common error type for validation errors of all kind of constraints
  • Accumulation of multiple constraint violations
  • Separation of the validation process itself and presentation of validation errors
  • The ValidationError is designed to help with composing detailed and helpful error messages targeted to the users of an application. Localization or internationalization of error messages is not scope of this crate.
  • The core functionality has no dependencies to 3rd party crates
  • Error codes are compatible with the naming convention in the fluent project
  • The error type ValidationError implements std::error::Error and can be used with the failure crate
  • Serialization and deserialization of ValidationError through serde (optional crate feature "serde1")
  • Support for widely used types of 3rd party crates through optional crate features
  • Support for BigDecimal of the bigdecimal crate (optional crate feature "bigdecimal")
  • Support for BigInt of the num-bigint crate (optional crate feature "num-bigint")
  • Support for DateTime and NaiveDate of the chrono crate (optional crate feature "chrono")

Usage

For detailed information on how to use valid including lots of examples see the API documentation at docs.rs.

To use valid we add it as a dependency to our Cargo.toml file:

[dependencies]
valid = "0.3"

valid provides some of its functionality as optional crate features. Some features enable support for validating a type that is provided by this crate. Other features enable the implementation of additional constraints. To use any optional functionality we must enable the relevant crate feature in our Cargo.toml file. All crate features can be enabled in any combination.

Here is an overview of all crate features:

crate feature supported types enabled constraints
bigint BigInt
bigdecimal BigDecimal
chrono DateTime, NaiveDate
regex Pattern

Additionally the "serde1" feature enables serialization and deserialization of ValdiationError using the serde crate:

[dependencies]
valid = { version = "0.3", features = ["serde1"] }

valid's People

Contributors

haraldmaida avatar

Stargazers

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

Watchers

 avatar  avatar

valid's Issues

Calling context.into() does not convert to State type

I'm following the docs and trying to call context.into to get the actual state object. But I just get unknown. Was I supposed to impl Into for my State type? Your docs don't seem to indicate that.

pub struct StreamConstraint;
pub struct StreamState;

impl StreamState {
    pub fn is_stream(val: Option<String>) -> bool {
        if let None = val {
            return false;
        }

        let stream = JsValue::from(val.clone());
        if stream.is_null() || !stream.is_object() {
            return false;
        }
        let emitter_result = serde_json::from_str::<EventEmitter>(val.unwrap().as_str());
        match emitter_result {
            Ok(_) => true,
            _ => false
        }
    }
}

impl<'a> Validate<StreamConstraint, State<&'a StreamState>> for String {
    fn validate(self, context: impl Into<State<&'a StreamState>>, constraint: &StreamConstraint) -> Validation<StreamConstraint, Self> {        
        if context.into().is_stream(Some(&self)) {
            return Validation::success(self);
        }
        Validation::failure(vec![invalid_state("invalid-stream", vec![])])
    }
}

Flat argument list instead of nested tuples for closures in `Validation` methods

Currently the closures in the methods Validation::and_then and Validation::map` get passed nested tuples which can become really ugly with more and more arguments.

We should find a way to flatten the values collected so far by the Validation type, so that the closures either get a list of arguments passed or one flat tuple with all the values.

This will be a breaking change in the API, but I think the advantage outweighs any pain with changing existing implementations.

Validation of constraints `Length` and `CharCount` might panic

The current implementation of Validate for the constraints Length and CharCount might panic. The limits are of type u32 and to perform the checks the limit values are casted to usize. If an actual value does not fit into usize it will panic. This might be the case on 16bit or 8bit targets.

Wonderful library! But it seems abandoned?

Wonderful library! But it seems abandoned?

I would like to thank the author, in my opinion, this tool can be a good alternative to other validation/parsing libraries (semval, garde, frunk).

Interested to know why there is no more activity?

As a continuation of the previous issue, i would like to ask a similar question that i encountered when trying to implement the same logic: about flattening values passed to the and_then closure.

It's still more than usable.

Moreover, there are language limitations (lack of partial application, automatic carrying) that prevent an elegant solution to this problem.

Thank you, author! =)

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.