bartoszlenar / Validot

Validot is a performance-first, compact library for advanced model validation. Using a simple declarative fluent interface, it efficiently handles classes, structs, nested members, collections, nullables, plus any relation or combination of them. It also supports translations, custom logic extensions with tests, and DI containers.
MIT License
298 stars 18 forks source link

IValidot interface #28

Open adambajguz opened 1 year ago

adambajguz commented 1 year ago

It would be useful to have a IValidator interface with object based IsValid and Validate methods. Also the new interface can expose a SpecifiedType property to easily access the type the validator is validating. This new interface will allow a non-generic code (e.g. in ASP.NET Core) to easily validate models.

    public interface IValidator<T> : IValidator
    {
        /// <summary>
        /// Quickly verifies whether the model is valid (according to the specification) or not.
        /// This is highly-optimized version of <see cref="IValidator{T}.Validate"/>, but it doesn't return any information about errors.
        /// </summary>
        /// <param name="model">The model to be validated.</param>
        /// <returns>True, if model is valid and there are no errors according to the specification. Otherwise - false.</returns>
        bool IsValid(T model);

        /// <summary>
        /// Validates the model against the specification. Returns <see cref="IValidationResult"/> object that contains full information about the errors found during the validation process.
        /// WARNING! The returned <see cref="IValidationResult"/> object is internally coupled with the instance of <see cref="IValidator{T}"/> that created it.
        /// It's safe to use its members to get the information you want and process them further, but don't cache the instance of <see cref="IValidationResult"/> itself or pass it around your system too much.
        /// </summary>
        /// <param name="model">The model to be validated.</param>
        /// <param name="failFast">If true, the validation process will stop after detecting the first error. Otherwise, full validation is performed.</param>
        /// <returns>Full information (in a form of <see cref="IValidationResult"/> about the errors found during the validation process, their location, messages and codes.</returns>
        IValidationResult Validate(T model, bool failFast = false);
    }

    public interface IValidator
    {
        /// <summary>
        /// Gets the type that is validated by the validator. It's T from IValidator{T}.
        /// </summary>
        Type SpecifiedType { get; }

        /// <summary>
        /// Gets settings of this <see cref="IValidator{T}"/> instance.
        /// </summary>
        IValidatorSettings Settings { get; }

        /// <summary>
        /// Gets the validation result that contains all possible paths and errors described in the specification.
        /// It's the specification in a form of <see cref="IValidationResult"/>.
        /// For collection, the path contains only '#' instead of the item's index.
        /// For reference loop's root, the error is replaced with the single message under the key 'Global.ReferenceLoop'.
        /// </summary>
        IValidationResult Template { get; }

        /// <summary>
        /// Quickly verifies whether the model is valid (according to the specification) or not.
        /// This is highly-optimized version of <see cref="IValidator{T}.Validate"/>, but it doesn't return any information about errors.
        /// </summary>
        /// <param name="model">The model to be validated.</param>
        /// <returns>True, if model is valid and there are no errors according to the specification. Otherwise - false.</returns>
        bool IsValid(object model);

        /// <summary>
        /// Validates the model against the specification. Returns <see cref="IValidationResult"/> object that contains full information about the errors found during the validation process.
        /// WARNING! The returned <see cref="IValidationResult"/> object is internally coupled with the instance of <see cref="IValidator{T}"/> that created it.
        /// It's safe to use its members to get the information you want and process them further, but don't cache the instance of <see cref="IValidationResult"/> itself or pass it around your system too much.
        /// </summary>
        /// <param name="model">The model to be validated.</param>
        /// <param name="failFast">If true, the validation process will stop after detecting the first error. Otherwise, full validation is performed.</param>
        /// <returns>Full information (in a form of <see cref="IValidationResult"/> about the errors found during the validation process, their location, messages and codes.</returns>
        IValidationResult Validate(object model, bool failFast = false);
    }
bartoszlenar commented 1 year ago

Hi @adambajguz , thank you for contribution.

Since it's a breaking change, I need to spend more time considering all aspects of it. Could you be more specific and provide an example where such generic-less IValidator interface would benefit the most? A situation where IValidator<T> is a pain and there is explicit need for just IValidator?

adambajguz commented 1 year ago

Hi @bartoszlenar, IValidator is useful when writing an integration with ASP.NET Core because model validation in ASP.NET Core doesn't use generics (more on that in #29). Also there is a HolderInfo class in Validot with CreateValidator() method that returns an object