Request Rate Limiting in Lumen 5.2

Categories: personal Tags: side note, Lumen 5.2, Lumen

Lumen 5.2 is possitioned as API friendly minimal framework with Laravel flavour. However when you start looking at API features you'll find that rate limiting that is present in Laravel 5.2 nowhere to be found in Lumen. This decision seems to be odd given the simplicity of implementation.

If you look at Laravel 5.2, you'll find that it has Middleware called "throttle". This particular middleware is capable of limiting requests and works using internal cache system. If you look at file itself, you'll see that it looks like greate opportunity for copy/paste and this is exactly what we're going to do.

Let's grab \Illuminate\Routing\Middleware\ThrottleRequests from Laravel 5.2 installation. If you do not have Laravel 5.2 instalation handy, you can always head over to github and grab file from there. Place file with the rest of your middleware files in app/Http/Middleware. Before this middleware can rate limit requests, we'll need to adjust it a bit. First of all we need to make sure it is namespaced correctly so change namespcae to

namespace App\Http\Middleware;

Next we'll need to update how fingerprint is created. Let's take a look at resolveRequestSignature function. Out of the box Laravel calls return $request->fingerprint(); but that function is missing in Lumen's Request implementation. Let's recreate it on middleware itself

protected function resolveRequestSignature($request)
{
    return sha1(
        $request->method() .
        '|' . $request->server('SERVER_NAME') .
        '|' . $request->path() .
        '|' . $request->ip()
    );
}

As you can see we take server name, path and IP to create unique "fingerprint" for the request. This value will be used as a key in storage and allow us to throttle requests.

Next, run composer dump-autoload and open bootstrap/app.php file. We're going to need to make our new middleware available aka "register" it. You'll find some templates for registering middleware right in the file, so we're going to add our new right bellow examples:

$app->routeMiddleware([
    'throttle' => App\Http\Middleware\ThrottleRequests::class,
]);

Now we need some routes to throuttle. Head over to app/Http/routes.php and add new route

$app->group(['middleware' => 'throttle'], function () use ($app) {
    $app->get('/', function () use ($app) {
        return $app->version();
    });
});

Now we need to make sure we have cache driver set to something other then array and we can test it. File system is fine, so update your .env file with CACHE_DRIVER=file. Default rate is 60 request per min 1 and we probably need to bring it down to something we can actually replicate, so let's adjust the route to allow 2 request every minute:

$app->group(['middleware' => 'throttle:2,1'], function () use ($app) {
    $app->get('/', function () use ($app) {
        return $app->version();
    });
});

Now, if you hit your homepage 3 times in a row you'll see Too Many Attempts in your browser and 429 response code from the server.