Laravel API uses Redis + Lua

Laravel already has Redis support out of the box, so we can use the Redis::eval() method to run Lua scripts.


1. Store the Lua Script (rate_limit.lua)

Put this in app/Services/Redis/rate_limit.lua:

lua

-- KEYS[1] = user key (e.g., "rate_limit:user123")
-- ARGV[1] = limit (max requests)
-- ARGV[2] = window (seconds)

local current = redis.call("INCR", KEYS[1])

if tonumber(current) == 1 then
    redis.call("EXPIRE", KEYS[1], ARGV[2])
end

if tonumber(current) > tonumber(ARGV[1]) then
    return 0 -- limit exceeded
else
    return 1 -- allowed
end

2. Create a Laravel Service Class

Make app/Services/RateLimiter.php:

php

<?php

namespace App\Services;

use Illuminate\Support\Facades\Redis;

class RateLimiter
{
    public static function attempt(string $userId, int $limit, int $window): bool
    {
        $script = file_get_contents(app_path('Services/Redis/rate_limit.lua'));

        $key = "rate_limit:{$userId}";

        $result = Redis::eval($script, 1, $key, $limit, $window);

        return $result === 1;
    }
}

3. Use It in a Controller (e.g., API Throttle)

Example in app/Http/Controllers/ApiController.php:

php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Services\RateLimiter;

class ApiController extends Controller
{
    public function handleRequest(Request $request)
    {
        $userId = $request->user()->id ?? $request->ip();

        // Allow max 5 requests per 60 seconds
        if (!RateLimiter::attempt($userId, 5, 60)) {
            return response()->json(['error' => 'Too Many Requests'], 429);
        }

        return response()->json(['message' => 'Request successful']);
    }
}

Test It:

  • Make 5 requests within 60s → allowed
  • On the 6th request → returns 429 Too Many Requests

Why This is Powerful

  • Uses Redis Lua for atomic, fast rate limiting.
  • Works across multiple app servers (not just one PHP instance).
  • Easy to tweak per-user, per-IP, or per-API-key.

You can also extend this so different API endpoints can have different rate limits (e.g., /login stricter, /profile looser). See Laravel: rate limiter for different API endpoints

By ice

Leave a Reply

Your email address will not be published. Required fields are marked *