Fluent Validation and ASP.NET Core 6 Web API

Viewed 199

I am new to fluent validation and also a beginner in Web API. I have been working on a dummy project to learn and your advice will be much appreciated. After following the FluentValidation website, I was able to successfully implement fluent validation.

However, my response body looks very different and contains a lot of information. Is it possible to have a regular response body with validation errors?

I will put down the steps I took to implement fluent validation. your advice and help are much appreciated. I am using manual validation because based on the fluent validation website they are not supporting the auto validation anymore.

In the program file, I added

builder.Services.AddValidatorsFromAssemblyContaining<CityValidator>();

Then I added a class that validated my City class which has two properties Name and Description:

public class CityValidator : AbstractValidator<City>
{
    public CityValidator()
    {
        RuleFor(x => x.Name)
                .NotNull()
                .NotEmpty()
                .WithMessage("Please specify a name");
        RuleFor(x => x.Description)
                .NotNull()
                .NotEmpty()
                .WithMessage("Please specify a Description");
    }
}

In my CitiesController constructor I injected Validator<City> validator; and in my action, I am using this code:

ValidationResult result = await _validator.ValidateAsync(city);

if (!result.IsValid)
{
    result.AddToModelState(this.ModelState);
    return BadRequest(result);
}

The AddToModelState is an extension method

public static void AddToModelState(this ValidationResult result, ModelStateDictionary modelState)
{
    if (!result.IsValid)
    {
        foreach (var error in result.Errors)
        {
            modelState.AddModelError(error.PropertyName, error.ErrorMessage);
        }
    }
}

On post, I am getting the response as

{
    "isValid": false,
    "errors": [
        {
            "propertyName": "Name",
            "errorMessage": "Please specify a name",
            "attemptedValue": "",
            "customState": null,
            "severity": 0,
            "errorCode": "NotEmptyValidator",
            "formattedMessagePlaceholderValues": {
                "PropertyName": "Name",
                "PropertyValue": ""
            }
        },
        {
            "propertyName": "Description",
            "errorMessage": "Please specify a name",
            "attemptedValue": "",
            "customState": null,
            "severity": 0,
            "errorCode": "NotEmptyValidator",
            "formattedMessagePlaceholderValues": {
                "PropertyName": "Description",
                "PropertyValue": ""
            }
        }
    ],
    "ruleSetsExecuted": [
        "default"
    ]
}

While the regular response without Fluent Validation looks like this:

{
    "errors": {
        "": [
            "A non-empty request body is required."
        ],
        "pointofInterest": [
            "The pointofInterest field is required."
        ]
    },
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-1a68c87bda2ffb8de50b7d2888b32d02-94d30c7679aec10b-00"
}

The question: is there a way from the use the fluent validation and get the response format like

{
    "errors": {
            "": [
                "A non-empty request body is required."
            ],
            "pointofInterest": [
                "The pointofInterest field is required."
            ]
        },
        "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
        "title": "One or more validation errors occurred.",
        "status": 400,
        "traceId": "00-1a68c87bda2ffb8de50b7d2888b32d02-94d30c7679aec10b-00"
    }

Thank you for your time.

1 Answers

Updated ans:

with your code, you can simply replace.

 return BadRequest(result); // replace this line with below line.
 return ValidationProblem(ModelState);

then you get same format as required.

enter image description here

------------------------*----------------------------------------

Please ignore this for manual validation.

You don't need explicit validation call.

this code is not required:

ValidationResult result = await _validator.ValidateAsync(city);

if (!result.IsValid)
{
    result.AddToModelState(this.ModelState);
    return BadRequest(result);
}

it will auto validate the model using your custom validator.

you simply need this

if (!ModelState.IsValid)
{
   return BadRequest(ModelState);
}

and it will give you errors in the require format.

Related