Building a Rate-Limiting Middleware for Your API in Laravel

Building a Rate-Limiting Middleware for Your API in Laravel

BackerLeader posted 3 min read

When building APIs, one of the biggest challenges is preventing abuse and overloading your server with too many requests. Whether it’s a malicious bot or a misconfigured script, an uncontrolled request rate can degrade performance and even crash your app.

That’s where rate-limiting comes in — it helps you control how often a client can hit your API within a specific time frame.

In this post, I’ll walk through how to create a custom rate-limiting middleware in Laravel, understand how Laravel’s built-in system works, and explore best practices for implementing it efficiently.


What is Rate-Limiting?

Rate-limiting is the process of restricting how many times a user or client can make a request to your API within a given timeframe (e.g., 100 requests per minute).

It’s an essential part of modern API security and performance optimization. Without it, your API could face issues like:

  • Denial of Service (DoS) from excessive requests
  • Increased server load and latency
  • Data abuse from unauthorized automation

⚙️ How Laravel Handles Rate-Limiting by Default

Laravel already includes a rate-limiting feature via its ThrottleRequests middleware, which works with API routes by default.

You can find it defined in your app/Http/Kernel.php file under the 'api' middleware group.

'api' => [
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

Laravel’s default API rate limiter allows 60 requests per minute per user/IP.

You can customize this behavior in the RouteServiceProvider:

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

protected function configureRateLimiting()
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
    });
}

This configuration tells Laravel:

“Each user or IP can make up to 60 requests per minute.”


Creating a Custom Rate-Limiting Middleware

Now, let’s build our custom rate-limiting middleware from scratch.

This gives us more control — for example, we could apply different limits to different endpoints or user roles.

Step 1: Create the Middleware

Run this Artisan command:

php artisan make:middleware CustomRateLimiter

This creates a new file at app/Http/Middleware/CustomRateLimiter.php.


Step 2: Implement Rate-Limiting Logic

Edit the file and add the following code:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Cache;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class CustomRateLimiter
{
    protected $maxAttempts = 10;  // max requests
    protected $decaySeconds = 60; // time window in seconds

    public function handle(Request $request, Closure $next)
    {
        $key = sprintf('rate_limit:%s', $request->ip());
        $attempts = Cache::get($key, 0);

        if ($attempts >= $this->maxAttempts) {
            return response()->json([
                'message' => 'Too many requests. Please try again later.'
            ], Response::HTTP_TOO_MANY_REQUESTS);
        }

        Cache::put($key, $attempts + 1, $this->decaySeconds);

        $response = $next($request);
        $response->headers->set('X-RateLimit-Limit', $this->maxAttempts);
        $response->headers->set('X-RateLimit-Remaining', $this->maxAttempts - ($attempts + 1));

        return $response;
    }
}

What’s Happening Here?

  • We store each IP’s request count in the cache (Redis, file, or database depending on your config).
  • If the request count exceeds the limit (maxAttempts), we block further requests.
  • Otherwise, we increment the count and allow the request.
  • We also send back rate-limit headers (X-RateLimit-Limit and X-RateLimit-Remaining) so clients know their current quota.

Step 3: Register the Middleware

Open app/Http/Kernel.php and add your middleware under the $routeMiddleware array:

protected $routeMiddleware = [
    // ...
    'custom.throttle' => \App\Http\Middleware\CustomRateLimiter::class,
];

Step 4: Apply Middleware to Routes

Now, you can use it in your API routes.

Route::middleware('custom.throttle')->group(function () {
    Route::get('/data', [DataController::class, 'index']);
});

Or apply it to a single route:

Route::get('/user', [UserController::class, 'show'])->middleware('custom.throttle');

Bonus: Different Limits for Different Users

You can extend the logic to give premium users higher limits:

$key = sprintf('rate_limit:%s', $request->user()?->id ?: $request->ip());
$limit = $request->user()?->isPremium() ? 100 : 20;

Then replace $this->maxAttempts with $limit in your logic.


Best Practices for API Rate-Limiting

Tips: 1. Store rate-limit data in Redis for speed and reliability. 2. Return rate-limit headers so clients can self-throttle. 3. Combine with authentication for user-specific control. 4. Monitor blocked requests using logging or metrics.

Why This Matters

Rate-limiting is not just a security feature — it’s also about stability and fair resource allocation.
By controlling API usage, you ensure all clients get consistent performance and protect your infrastructure from overload.


✅ Conclusion

Building your own rate-limiting middleware in Laravel is a great exercise to understand how requests flow through your application.

Even though Laravel provides a powerful built-in system, having custom control lets you tailor performance and protection to your specific project needs.

Start small — protect a few routes, test, and iterate as your API grows.

With this setup, you’re one step closer to building a robust, production-ready Laravel API.

3 Comments

0 votes
0 votes
0 votes
0

More Posts

Protecting Your Laravel API from DDoS Attacks: Best Practices

Gift Balogun - Oct 13

Learn to manage Laravel 10 queues for efficient job handling and implement real-time notifications seamlessly.

Gift Balogun - Jan 1

10 Simplified Laravel 10 Performance Hacks You Can Use Today

Gift Balogun - Apr 30

Laravel Middleware: How To Craft Your Own HTTP Gatekeepers.

Darlington Okorie - May 19

Mastering Laravel Task Scheduling for Automated Jobs (Compatible with Laravel 10, 11 & 12)

Gift Balogun - Oct 29
chevron_left