Giter Site home page Giter Site logo

valit-stack / valit Goto Github PK

View Code? Open in Web Editor NEW
320.0 17.0 26.0 12.7 MB

Valit is dead simple validation for .NET Core. No more if-statements all around your code. Write nice and clean fluent validators instead!

License: MIT License

C# 98.57% PowerShell 1.00% Shell 0.43%
validation fluent-api dotnet core

valit's People

Contributors

arekbal avatar bovorasr avatar dbarwikowski avatar goorion avatar paw3lx avatar timdeschryver 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

valit's Issues

Move back to proper namespaces

Instead of having just one global namespace (Valit) @arekbal suggested to use it in a proper way, but all classes/extensions/enums etc. that are exposed to the user should be put inside "metadata" folder with its name staring with underscore (like _Valit). Thanks to that we'll be able to find all of the exposed classes inside the project (will be very handy even more when project will grow a lot).

Integrating with Autofac

Would be cool to create an integration package for Autofac. There are lot's of thing that we could add here so hesitate to add something in the comments ;) The simplest integration would be:

containerBuilder.RegisterValit();

Calling that we would look through the assembly and register all valitators as singletons.

Add basic tests

Add some basic tests for:
-Int16
-Int32
-Int64
-UInt16
-UInt32
-UInt64
-Single
-Double
-Byte
-Decimal
-Boolean
-String

Remove IValitRulesProvider

This issue is related to the discussion started in #151 . Basically @tdeschryver suggested removing IValitRulesProvider since it's not used for nested objects validation anymore. Then instead of doing:

ValitRules<Model>
    .Create(provider.GetRules())

we could simply pass another IValitRules object instead:

ValitRules<Model>
    .Create(anotherValitRules)

This would also remove the confusion about the GetRules() method since it's not clear whether it returnes IValitRules or collection of IValitRule. Looking forward for your opinion on that one :)

Support for Infinity on float and double

We should consider validation for Infinity in double and float. It might be tricky and honestly I don't know how how rules are implemented in C#. It's not super important imho.

Tagging rules for collections - expected behavior

As you can see, I added support for collections using EnureFor() method (PR #120). The issue I noticed is related to the tagging.

The whole concept of supporting collection for either primitive types or nested objects is based on separated implementations of IValitRule<TObject, TProperty> interface, so:

  • NestedObjectCollectionValitRule
  • CollectionValitRule

The idea was to aggregate all rules for collections using just one class. Why? Simply because at the point of doing EnsureFor() we don't have the actual object hence we can't invoke the selector and iterate over the collectiom. So, it's a little bit like "lazy evaluation" when Validate() method is called an the object is passed to this method. The issue I have is that user may tag the rules inside EnsureFor() like in the example below:

...
.EnsureFor(m => m.Emails, _=>_
    .Required().Tag("A")
    .Email().Tag("B"))

But as I wrote, all these rules inside this method are evaluated during the validation. Therefore if user would do something like:

...
.EnsureFor(m => m.Emails, _=>_
    .Required().Tag("A")
    .Email().Tag("B"))
.GetTaggedRules()

He wouldn't get any result, because what was actually stored inside IEnumerable<IValitRule<TObject>> was the instance of CollectionValitRule which was not tagged by the user.

What really sucks is that actually I have no idea what behavior is correct in this particular scenario. Is this a bug or a feature? :D We need to discuss it until my PR will be merged.

Change When predicate

Currently When() takes Func<bool> as the param but as we switched to IValitRule<TObject,TProperty> we can change it to Predicate<TObject>.

Support for nested object

We should support validation for nested objects. As we discussed couple weeks ago we could provide a generic interface for our validator class like:

public interface IValitator<in TObject>
{
    IValitResult Validate(TObject @object, IValit strategy strategy = null);
}

And then create an overload on the Ensure() method which could get the instance of this validator instead of rules set:

...
.Ensure(m => m.NestedModel, new NestedModelValidator())

I'm still not quite convinced about an overload, maybe some extension method like:

.Ensure(m => m.NestedModel, _=>_
   .WithValitator(new NestedModelValidator))

It's worth mentioning that the reason for putting strategy as a validator parameter is that doing this we can propagate chosen strategy (in the "root object") to the nested ones.

What are your thoughts about that guys?

Add time~ tests

We need testes for:

  • DateTime
  • DateTimeOffset
  • TimeSpan

Requested coverage is 100%

Broken develop

Something weird happend to develop :/ Today I merged develop into master (with rebase) to create a release for version v0.2.0. After a while I realized that I forgot to change the version inside csproj file. I did the change on the develop and I created another PR from develop into master. It turned out that the PR contained all commmits (38) and changes (213) from from 0.2.0 once again. I updated the develop using the UPDATE button and... poof...

PR shown correct change (so just one change inside csproj) but develop has now duplicated commits from 0.2.0... I have no idea what happened! Now comes the best part. I didn't want to have a mess inside master so I squashed all these changes into one commit and merged it into master. So great, master has just one more commit since 0.2.0 merge with updated csproj. I wanted to test what would happend if I'll do some change on the develop once again. I did small change in the README, created new PR from develop to into master and... same story... I contains all commits and changes from 0.2.0... Do you have any idea what caused that? What options we have to fix that. The only one I have is to create new develop from master (tested that and worked as expected).

I'm sorry guys, that's probably my fault... But I swear, I've never had simmilar issue before...

Integrating with ASP.NET Core

I think that having the very solid Core library, we should start thinking about some integration projects and here comes the first one. I thought about creating new NuGet for the ASP.NET Core apps. The idea is simple, allow folks to kick off the validation before we start processing the particular action in the MVC6 controller, so the could use ModelState object to see the result (just like it was achieved before using the attributes). So to me the whole process should look as follows:

  1. Someone creates a new Model type
  2. Coresponding ModelValitator is created for type
  3. In Startup we register of valitators autmatically using UseValit() extension
  4. When the MVC controller receives the object in the body we can handle the validation like below:
public async Task DoSomethingAsync(Model model)
{
    if(! ModelState.IsValid)
    {
        return BadRequest(ModelState.Errors);
    }
    ....
}

That would be awesome ๐Ÿ‘

Add support for variable messages at runtime

E.g. for translation of the error messages depending on user's culture.

Basic usage would be something along the lines of
.WithMessage(()=> _translationService.GetError("Missing_Email"))

Add extension methods for DateTime

I noticed that we have very poor support for DateTime. We need couple methods which might be handy for people like:

  • IsLaterThan(Datetime dateTime)
  • IsEarlierThan(Datetime dateTime)
  • IsLaterThanNow()
  • IsEarlierThanNow()

Add support for Guid and Nullable<Guid>

I noticed that we still miss support for Guid type. If you have any suggestions about extension methods that could be useful, just write them below :) My thought was:

  • IsNotEmpty
  • IsEqualTo
  • IsRequired (for nullable)

Validating nested objects - passing the IValitator<TObject>

Currently to validate a nested object we need to pass the IValitRulesProvider object to Ensure method. Actually we could pass IValitator object instead since there's no problem with that and we could simply a code even more. Honestly I don't why I didn't do this at the first time :D

Asserts in tests

I was dabbling around and noticed the Assert.Equal methods in the tests are having the wrong signature.
For example:
Assert.Equal(result.Succeeded, expected);
should be:
Assert.Equal(expected, result.Succeeded);

Is it OK to change this (Assert.True and Assert.False) by using Shouldly?
This way all our tests are written with Shouldly.

Add support for Nullable<T>

Currently we don't support nullable types. Since they are very common we need overloads for most of our validation rules.

Add support for message keys

We should support adding message keys besides "classic" messages.

Tasks:

  • Provide interface for message keys provider
  • Add WithMessageKey extension method
  • Modify ValitRules, so it can get proper messages inside Validate method

Create Generic tests for Int and UInt

We need tests for integers:
-Int16
-Int32
-Int64
-UInt16
-UInt32
-UInt64

and nullable integers:
-Int16?
-Int32?
-Int64?
-UInt16?
-UInt32?
-UInt64?

Ideally we will have two generic classes which will handle most cases and 12 inherited classes which will contain more specific checks

problems in ValitRuleExtension methods

There are problems in ValitRuleExtensions which surfaced with my PR.

Methods: Required, IsEqualTo, IsGreaterThan, IsLessThan, MinLength, MaxLength, Matches handle null improperly.

In Required
p.Equals(default(TProperty)) tries to handle default values such as int equal 0 as incorrect 'unrequired' value which is a very specific case... and imho requires specific, strongly typed extensions. Such as _=>_.Id)(_=>_.IsPositive())

Inside IsEqualTo
Given x.prop = null and y.prop = null
Object.Equals(x.prop, y.prop) makes sense when comparing two objects for similarity without given context.

IMO, user - in case he wants to not let null pass - should have to be more specific and add Required to handle null there.

Similarly with IsGreaterThan.
When ordering int? it makes sense to make the value null as being lower than 4. What IMO we want from user is to - again - be explicit about handling null with Required on Nullable types or additional param.

And I dont like the way we oversimplify handling of these numbers... (separate overloads in separate namespaces?) floats and doubles can be NaN...

Also, Methods MinLength, Maxlength and Matches could handle these string-like types safer and without typeof with a string copy from IEnumerable<char> such as new string(p.ToArray()).

For plain strings I would suggest separate overload in separate namespace.

For instance:
public static class ValitRuleStringExtensions { public static IValitRule<TObject, string> MinLength<TObject>(this IValitRule<TObject, string> rule, int length) where TObject : class { rule.ThrowIfNull(ValitExceptionMessages.NullRule); return rule.Satisfies(p => p.Length >= length); } }
there is no magic or casts about it... ;)

Classes with very specific overloads for all the basic types. Drop the typeof where possible...

So again I am not sure if these string validation extensions should require themselves input to not be null...
So the question is:

  1. .Required("missing value, Dude").MaxLength(5, "Input Value '{0}' is longer than {1}")
    or just
  2. .MaxLength(5, "Input Value '{0}' is longer than {1} or maybe null?!?")
    or just treat
  3. .MaxLength(5, "Input Value '{0}' is longer than {1}")
    same as calling
    .Required().MaxLength(5, "Input Value '{0}' is longer than {1}")
    where Required gets some default message customisable in "context" configuration.
    I think the ideal case for this specific example is to allow both (1 and 3).

Add summary for every method/class

Currently we don't have any summary for classes and methods as well. As far as I know, this is highly requested by folks who could probably use Valit.

Add more things for customising error messages

I'd be cool if we could add more things for customising error messages. I thought about something very simple like "tokens" which we could put into the string which then would be replaced with something like "{displayName} is required". I thought about the following tokens:

  • propertyName
  • displayName
  • value

The above would imply adding new extension method - WithDisplayName()

New rule: String required

๐Ÿ‘‹ all,

Would it make sense to add a String.Required rule, or should String.MinLength be used here?
This rule would do the check via string.IsNullOrWhiteSpace().

I can create a PR if this gets expected.

Suggested small changes

Hi,

First of, great project here (found it via c# digest)!
After contributing yesterday, I would suggest these small changes - I'm willing to create PRs for the ones that get accepted ๐Ÿ˜„

  • Small change to .gitignore because right now every file from ./tools will be commited when someone builds the project via the build scripts
  • Add dotnet-watch, so it would be possible to do dotnet watch test
  • Add .editorconfig
  • Add .gitattributes?

Add support for error codes

We should support putting error codes besides "classic" messages.

Tasks:

  • Modify ValitRule so it can keep set of error codes
  • Add WithErrorCode extension method

Support for Epsilon on double and float

Currently we don't support Epsilon in extensions for double and float. The suggestion is that each method should have default parameter like:

(this IValitRule<TObject, double> rule, double value, double epsilon = 0.0d)

so user can specify it, but it's not required. Each method should then consider this number in the calculations. Need to applied for:

  • IsGreaterThan()
  • IsLessThan()
  • IsEqualTo()
  • IsPositive()
  • IsNegative()
  • IsNonZero()

Features for v1.0.0

Version 0.2.0 was released two days ago, o I think we can start thinking about features for next release. If you have any suggestions, please put them in the comments below :)

For a now we'll definitely, add:

  • Support for comparing two properties described in #114

Move For() to IValitRules<TObject> explicit implementation

Since For(TObject @object) is static initialize method, we have to pass the object even if we just want to execute set of rules.

Tasks:

  • Move For() to IValitRules<TObject>
  • Create static initialize method like Create with optional parameter -
    IEnumerable<IValitRule<TObject>>

Docs 0.2.0

Does anyone could help me with docs for next release? PLEASE!

We need to add:

Inside "Validation rules"

  • Required() for string in "Available validation rules"
  • Add bool rules inside "Available validation rules"
  • "Validating nested objects" section after "Available validation rules"
  • "Validating collections" section after "Validating nested objects"

We also need to add new page called "Valitators" and describe how to create them from:

  • IValitRulesProvider<TObject>
  • IValitRules<TObject>

Support for System.ComponentModel.DataAnnotations

There are - in .net - basic built in validation components, which our validation system should support in some later versions. Most of them are placed in assembly+namespace: System.ComponentModel.DataAnnotations
MaxLengthAttribute and so on...

Refactor resolving IValitResult from rules collection

Currently we have 3 places where the code responsible for getting the result from rules is duplicated:

  • ValitRules
  • NestedObjectValitRule
  • NestedObjectCollectionValitRule

Would be cool if we could get rid of this somehow ๐Ÿ‘

Support for comparing two properties

I think it could be nice to have ability to compare two properties of an object:

.Ensure(m => m.Password, _ => _.IsEqualTo(m => m.RePassword))

What do you think about it?

Remove Required on value types

Currently we can do something like this:


....
.Ensure(model => model.IntValue)
.Required()
...

The problem with the above approach is that we use default(TProperty) inside the condition. Due to that fact if IntValue equals 0, Required rule is not satisfied. We should change that. The suggested solutions are:

  • Add overload for Required which takes a "strategy" how 0 should be treated
  • Remove Required on value types and add only .IsPositive() and .IsNegative() methods
  • I also think about something more general like .IsNonDefault()

I'm open for more suggestions on that one guys ;)

Authors file

Guys, I'd like to add AUTHORS.txt file inside the project so folks can see the full list of contributors + their emails to contact. If you don't mind, please give me your emails that you'd like to put inside.

Framework tests

We need to test:

  • Strategies
    • Complete
    • FailFast
  • Exceptions
    • SemanticExceptions
    • ValitExceptionExtensions
    • ValitExceptionMessages
  • ValitRules class
  • ValitRule class
  • ValitRuleAccessorExtensions
  • ValitResult
  • EmptyMessageProvider
  • ValitRuleError

Default error messages

I think it would be nice to have a default messages for all validation rules. Notice that in most cases you would write message like:

.Ensure(m => m.IntValue, _=>_
    .IsGreaterThan(2)
    .WithMessage("IntValue is not greater than 2"))

... and so on. What I'm trying to say is that in many cases the actual message would be quite predictable :D That's why I thought about populating the ErrorMessages array in the IValitResult with default messages. Of course using WithMessage() would replace that with the custom one. I guess that, this feature wouldn't work with the Error Codes because eveybody has completely different system for doing that.

Add support for tags

We should support adding tags, so we can group and validate specific set of rules.

Tasks:

  • Modify ValitRule so it can keep set of tags specified by user
  • Add Tag() extension method for ValitRule
  • Add overload for Validate() which will take set of chosen tags and execute only these rules
  • Add properties/methods on ValitRules for receiving tagged/untagged rules

Nice to have:

  • Different strategies for validating tagged rules (have all, have at least one)

Resolve rules chain inside Validate

As you see we have a #114 almost done by @paw3lx. However we spotted that this feature requires the whole rules chain to be resolved inside Validate() method since the object is required as a one of the parameter of the selector. This will cause the inconsistency comparing to the previous solution where each chain is resolved inside ValitRules object (more precisely inside Ensure()). Now we have two options:

  1. Move all creations of rules chain to Validate() method to be consistent
  2. Get rid of old overloads which don't require second parameter, so the object (again to be consistent)

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.