Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom middleware for input validation

My API has only POST action method. I want to create a library which will validate the input to my API. Now I want to do this validation before hitting my controller action method.

I have decided to use Middleware approach -

public class ValidateInputMiddleware
{
    private readonly RequestDelegate _next;

    public ValidateInputMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        //read the request body

        //serialize the json body to input model

        //validations
        if(reqJsonObj.Id == null)
            //return response - id is null

        //other validations

        await _next(httpContext);
    }
}

If my validation condition is met then I don't want the other item in the pipeline to execute.

I need help with -

  1. How I can restrict other items in the pipeline from executing.

  2. How I can return customized error response in form of JSON.

like image 667
arpymastro Avatar asked Dec 19 '22 00:12

arpymastro


1 Answers

You should not use a custom middleware for this. Middlewares a very low-level and as you noticed, you will have to read and parse the request body yourself. Not only is that complicated but it also results in this happening twice (again inside the MVC middleware).

Instead, you should be using a MVC filter, in particular an action filter. Filters run as part of the MVC pipeline, so you can depend on various things that the MVC pipeline already does for you, e.g. model binding or authorization.

It also makes it easier to abort the response and return a custom JSON response instead, since you again won’t have to manually serialize your content but instead can use the high-level MVC results.

An action filter for your situation could look like this:

public class InputValidationActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // we can even *still* use model state properly…
        if (!context.ModelState.IsValid)
        {
            var responseObj = new {
                successful = false,
                error = "The input is not valid",
            };

            // setting the result shortcuts the pipeline, so the action is never executed
            context.Result = new JsonResult(responseObj)
            {
                StatusCode = 400
            };
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    { }
}
like image 134
poke Avatar answered Jan 02 '23 09:01

poke