Skip to content

Latest commit

 

History

History
122 lines (93 loc) · 4.53 KB

File metadata and controls

122 lines (93 loc) · 4.53 KB

AppAny.HotChocolate.FluentValidation

License Nuget Downloads Tests codecov

Feature-rich, but simple, fast and memory efficient input field HotChocolate + FluentValidation integration ⚡️

🔧 Installation

$> dotnet add package AppAny.HotChocolate.FluentValidation

💡 Features

🚩 You don't pay for validation middleware if the field has no validatable inputs

🚩 You are not validating, and even trying to validate empty or not marked as validatable inputs

🚩 Most of extensibility points are just composable delegates

🚩 Fine-tuning of validation for each field: conditional validation skipping, multiple validators or error mappers per input

🚩 Strongly typed ValidationStrategy<T> support

🚩 First-class attribute-based approach support

🎨 Usage

✅ Add FluentValidation validator

public class ExampleInput
{
  public string Example { get; set; }
}

public class ExampleInputValidator : AbstractValidator<ExampleInput>
{
  public ExampleInputValidator()
  {
    RuleFor(input => input.ExampleProperty)
      .NotEmpty()
      .WithMessage("Property is empty");
  }
}

✅ Configure HotChocolate + FluentValidation integration

# Since 10.2.0 https://github.com/FluentValidation/FluentValidation/releases/tag/10.2.0
services.AddFluentValidation();

services.AddGraphQLServer()
  .AddFluentValidation();

descriptor.Field(x => x.Example(default!))
  // Explicit over implicit preferred
  // You have to add .UseFluentValidation()/attribute to all arguments requiring validation
  .Argument("input", argument => argument.UseFluentValidation());

... Example([UseFluentValidation] ExampleInput input) { ... }

✅ Extend and customize

services.AddGraphQLServer()
  .AddFluentValidation(options =>
  {
    options.SkipValidation(...)
      .UseErrorMapper(...)
      .UseInputValidators(...);
  });

descriptor.Field(x => x.Example(default!))
  .Argument("input", argument => argument.UseFluentValidation(options =>
  {
    options.SkipValidation(...)
      .UseErrorMapper(...)
      .UseInputValidators(...)
      .UseValidationStrategy(...)
      .UseValidator<ExampleInputValidator>()
      .UseValidator<ExampleInput, ExampleInputValidator>()
      .UseValidator<ExampleInput, ExampleInputValidator>(strategy =>
      {
        strategy.IncludeProperties(input => input.ExampleProperty);
        // ...
      });
  }));

... Example([UseFluentValidation, UseValidator((typeof(ExampleInputValidator))] ExampleInput input) { ... }

📝 Docs

♿️ Benchmarks 🚀

🚧 I swear I will check correctness, run these benchmarks on my own environment and only after that I will make conclusions 🚧

Breaking changes

  • From 0.10.x to 0.11.x
    • Replace ValidationDefaults.Interceptors static class with ValidationDefaults.Interceptor property
    • Replace ValidationInterceptors static class with ValidationInterceptor : TypeInterceptor class
  • From 0.9.x to 0.10.x
    • Update HC version to 13 preview
  • From 0.6.x to 0.7.x
    • Default input validator throws InvalidOperationException if argument has [UseFluentValidation], but no validator registered in IServiceCollection