Basic Laravel Middleware - How to Apply the Same Code to All Requests

August 2020 | John Binzak
How to apply the same logic to each Laravel request with Middleware.

Overview

Sometimes when building web apps and restful APIs, it is ideal to apply the same logic to each request, before we get to the actual request logic. Think about . We might want to have a middleware that validates and retrieves the user id before each request. The way this is done with is with .

Create Middleware File

First let's create the class for our middleware code in . We will call it for this demo, but ideal it's best to name it specific to the intended function. For example if you create a third party API and want to check API keys before each request, you might want to name the class something like . It's also best to not have a single catch all middleware, but rather one per feature/function. This file should hopefully never be huge. Below is our basic class:


class MyCustomMiddleware{

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next){

        // continue
        return $next($request);
    }

}

Right now, all we are doing is passing the as is, without any logic.

Register the Middleware

Next we need to register the middleware with our app. We will do this in by adding an element to . We register the middleware as a key/value pair, where the key is the name shortcode. We will use this name shortcode in our Controllers so let's name it something straight forward such as .


    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'my-custom-middleware' =>  \App\Http\Middleware\MyCustomMiddleware::class,
    ];
    

Now there are other 2 other ways we can register our middleware with our app (all in the same file). One being the group. By adding the middleware to this array, we will apply our middleware to request. This can be beneficial for security or maybe , but for this example we want more finite controller.

The second way is to add our middleware to the array. This is the in between registration. We can create groups of middleware an apply them to certain requests. For example we could have a middleware for all web request.

Set Data in Middleware

Before we link our middleware to a controller, let's give it some basic data to pass through. We will give the request 3 new data fields. One from a , the next from a , and the last being a custom timestamp. We will be able to access this data in our controller.


    public function handle($request, Closure $next){

        // set from url param
        $request->test_key = $request->has('test_key') ? $request->input('test_key') : 'foo';

        // set from header
        $request->my_header = $request->header('x-custom-header');

        // set constant
        $request->blah = date("Y-m-d H:i:s");

        // continue
        return $next($request);
    }
    

Apply Middleware to Controller

Now let's apply the middleware to a specific controller. We will do so in the of the controller and by using the we specified while registering the middleware with our app. The middleware will now be apply to all endpoints in this controller.

Within a given endpoint we can now access the data we created in .


class TestController extends Controller
{

    public function __construct(){
        $this->middleware('my-custom-middleware');
    }

    public function test_abc(Request $request){

        // check if data field is set and non-empty, if so let's use it, otherwise use the default
        $data = [
            "test_key" => isset($request->test_key) && !empty($request->test_key) ? $request->test_key : 'NO TEST KEY',
            "my_header" => isset($request->my_header) && !empty($request->my_header) ? $request->my_header : 'NO HEADER',
            "blah" => isset($request->blah) && !empty($request->blah) ? $request->blah : 'NO BLAH'
        ];

        // response
        return response()->json($data, 200);
    }

}

Exclude Middleware from Route

If we want to exclude the middleware from a route or multiple routes within the controller, we can do so easily by adding an array with the the route function name to the middleware function in the controller .


class TestController extends Controller
{

    public function __construct(){
        $this->middleware('my-custom-middleware', ['except' => ['test_xyz']]);
    }

    public function test_abc(Request $request){

        // check if data field is set and non-empty, if so let's use it, otherwise use the default
        $data = [
            "test_key" => isset($request->test_key) && !empty($request->test_key) ? $request->test_key : 'NO TEST KEY',
            "my_header" => isset($request->my_header) && !empty($request->my_header) ? $request->my_header : 'NO HEADER',
            "blah" => isset($request->blah) && !empty($request->blah) ? $request->blah : 'NO BLAH'
        ];

        // response
        return response()->json($data, 200);
    }

    public function test_xyz(Request $request){

        // check if data field is set and non-empty, if so let's use it, otherwise use the default
        $data = [
            "test_key" => isset($request->test_key) && !empty($request->test_key) ? $request->test_key : 'NO TEST KEY',
            "my_header" => isset($request->my_header) && !empty($request->my_header) ? $request->my_header : 'NO HEADER',
            "blah" => isset($request->blah) && !empty($request->blah) ? $request->blah : 'NO BLAH'
        ];

        // response
        return response()->json($data, 200);
    }

}

Deny Requests from the Middleware

Denying a request from the middleware is the same as we would do in a normal route function.


    public function handle($request, Closure $next){

        // set from url param
        $request->test_key = $request->has('test_key') ? $request->input('test_key') : 'foo';

        // set from header
        $request->my_header = $request->header('x-custom-header');

        // set constant
        $request->blah = date("Y-m-d H:i:s");

        // deny requests without a custom header value
        if(empty($request->my_header)){
            return response()->json(['error' => 'No custom header value found!'], 400);
        }

        // continue
        return $next($request);
    }
    

Summary

So there you have it. We've just created a simple for our app. This is a great way to add some security to your app (although I recommend you look at a 3rd party library for that) and a great way to organize common code. You can find the source code here.