Skip to content

FluentValidation middleware for HotChocolate GraphQL

License

Notifications You must be signed in to change notification settings

dalrankov/FluentChoco

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FluentChoco

FluentValidation middleware for HotChocolate GraphQL

NuGet Version NuGet Downloads

How it works?

Registered FluentValidation middleware will be executed on top of GraphQL field and validate every argument value with it's registered IValidator<T> implementation from IServiceProvider. Validation failures, if there are any, will be reported and displayed in the response and request execution will be terminated.

Usage

There are two ways to add FluentValidation middleware: globally (for every field) and per-field.

Global:

services.AddGraphQLServer()
    .UseFluentValidation();

Code first:

descriptor.Field("demo")
    .UseFluentValidation();

Pure code first:

[UseFluentValidation]
public string Demo() => "All good!";

Keep in mind that adding middleware both globally and per-field will end up in field arguments being validated twice.

Validators registration

There is an easy way to automatically register all validators from your assembly. Also, by specifying parameters you can modify their lifetime and choose whether you want to inspect only public (exported) types or rather all types. By default, only public (exported) types will get inspected and validators will be registered with Transient lifetime.

services.RegisterFluentValidators<Startup>();

Validator customization

There are 3 ways to customize your validator's behaviour for each argument.

  • Skip validation
  • Specify the rule sets to validate
  • Specify the properties to validate

Code first:

descriptor.Field("demo")
    .Argument("input1", d => d.ValidateRuleSets("CustomRule"))
    .Argument("input2", d => d.ValidateProperties("Foo", "Bar"))
    .Argument("input3", d => d.SkipValidation());

Pure code first:

public string Demo(
      [ValidateRuleSets("CustomRule")] TestInput input1,
      [ValidateProperties("Foo", "Bar")] TestInput input2,
      [SkipValidation] TestInput input3)
    {
        return "All good!";
    }

Error customization

You can implement IValidationErrorBuilder to build your own errors.

public class CustomErrorBuilder
    : IValidationErrorBuilder
{
    public IErrorBuilder BuildError(
        IErrorBuilder builder, 
        ValidationFailure failure, 
        IInputField argument, 
        IMiddlewareContext context)
    {
        return builder.SetCode("DEMO_ERROR")
            .SetMessage(failure.ErrorMessage)
            .SetExtension("custom1", "Hey, there was an error!");
    }
}

Global:

services.AddGraphQLServer()
    .UseFluentValidation<CustomErrorBuilder>();

Code first:

descriptor.Field("demo")
    .UseFluentValidation<CustomErrorBuilder>();

Pure code first:

[UseFluentValidation(typeof(CustomErrorBuilder))]
public string Demo() => "All good!";

Icon made by Ivana Vujačić.