FluentValidation middleware for HotChocolate GraphQL
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.
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.
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>();
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!";
}
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ć.