Rate limiting is critical for protecting app or website resources from excessive or improper use. Whether a result of malicious human intervention, bot-based attacks, or an overlooked vulnerability, resource misuse can interfere with legitimate access to your application and introduce severe vulnerabilities.
This article explores how to add rate limiting to an API in a Laravel application.
Throttle Your API Traffic in Laravel
Rate limiting is a mechanism designed to mitigate the exploitation of your application’s resources. While it has many uses, it is particularly useful for public APIs in large, scalable systems. It ensures that all legitimate users retain fair access to system resources.
Rate limiting is also crucial for security, cost control, and overall system stability. It can help prevent request-based attacks, such as distributed denial-of-service (DDoS) attacks. This attack relies on sending repeated requests to overwhelm and disrupt access to an application or website server.
There are several methods for implementing rate limiting. You can use variables that characterize the requester to determine who can access your application and how frequently. Some common variables include:
- IP Address — Implementing rate limits based on IP addresses enables you to restrict the number of requests per address. This method is especially beneficial in circumstances where users can access an application without providing credentials.
- API Key — Limiting access via API keys entails providing the requester with pre-generated API keys and establishing rate limits on a per-key basis. With this approach, you can also apply different access levels to the generated API keys.
- Client ID — You can also pre-generate a Client ID that a user can embed in the header or body of API requests. This method lets you set per-ID access levels to ensure no client can monopolize system resources.
Laravel Middleware
Middleware provides a convenient mechanism for inspecting and filtering HTTP requests entering an application. Essentially, it’s a layer of code between the application and its underlying infrastructure to enable communication among its resources.
How To Implement Rate Limits
This tutorial uses an existing mini library API on the Laravel 10 framework to demonstrate using Laravel Throttle. The sample starting project contains the basic create, read, update, and delete (CRUD) implementations needed to manage books in a collection and two extra routes to demonstrate some rate-limiting concepts.
Prerequisites
The tutorial assumes you are familiar with the basics of API development in Laravel. Ensure that you have the following:
- PHP 8.2, Composer, and Laravel installed and configured on your local machine
- An active Kinsta account
- An account on GitHub, GitLab, or Bitbucket to push your code
You also use MyKinsta to set up and deploy this API. You can follow along with the provided project template and preview the final result from the complete source code.
Laravel Application Set Up
- To begin, clone the project template.
- Then, create a .env file in the project’s root directory and copy the contents of .env.example into it.
- Next, complete the setup using the following commands to install the application dependencies and generate the app key.
composer install
php artisan key:generate
If this command does not automatically add the app key to your .env file, run php artisan key:generate --show
, copy the generated key, and paste it into your .env file as the value for APP_KEY
.
- Once the dependencies installation and app key generation are complete, start the application using the following command:
php artisan serve
This command starts the application and makes it accessible via the browser at https://127.0.0.1:8000
.
- Visit the URL to confirm that the Laravel welcome page populates:
Database Configurations
Let’s configure and set up the application database in MyKinsta.
- Navigate to your MyKinsta account dashboard and click the Add service button:
- On the Add service list, click Database and configure the parameters to start your database instance:
This tutorial uses MariaDB, but you can choose any of the Laravel-supported database options that Kinsta provides.
- Once you’ve entered your database details, click the Continue button to finalize the process.
Databases provisioned on Kinsta have internal and external connection parameters. You should use internal connection parameters for applications hosted within the same Kinsta account and external parameters for external connections. Therefore, use Kinsta’s external database credentials for your application.
- Copy and update the app database’s .env credentials with the external credentials shown in the screenshot below:
DB_CONNECTION=mysql
DB_HOST=your_host_name
DB_PORT=your_port
DB_DATABASE=your_database_info
DB_USERNAME=your_username
DB_PASSWORD=your_password
- After filling in the database credentials, test the connection by applying database migration using the command below:
php artisan migrate
If everything functions properly, you should see a response similar to that shown below.
- Next, use the following command to list the application routes and see the routes already implemented.
php artisan route:list
You should now see the available API endpoints:
- Start the application and confirm that everything still works fine. You can test these endpoints via the terminal using a tool like Postman or CURL.
How To Rate Limit in a Laravel Application
Several rate-limiting techniques are available for Laravel applications. You can block a set of IP addresses or enforce duration-based request limits based on a user’s IP address or user_id. Next, you apply each of these methods.
- Install the Laravel Throttle package using the following command:
composer require "graham-campbell/throttle:^10.0"
- You can also make additional changes to the Laravel Throttle configurations by publishing the
vendor configurations
file:
php artisan vendor:publish --provider="GrahamCampbell\Throttle\ThrottleServiceProvider"
How To Block IP Addresses
One rate-limiting technique allows you to block requests from a specified set of IP addresses.
- To begin, create the necessary middleware:
php artisan make:middleware RestrictMiddleware
- Next, open the created app/Http/Middleware/RestrictMiddleware.php middleware file and replace the code in the
handle
function with the snippet below. Ensure you adduse App;
to the list of imports at the top of the file.
$restrictedIps = ['127.0.0.1', '102.129.158.0'];
if(in_array($request->ip(), $restrictedIps)){
App::abort(403, 'Request forbidden');
}
return $next($request);
- In the app/Http/Kernel.php file, create an alias for this middleware app by updating the
middlewareAliases
array as follows:protected $middlewareAliases = [ . . . 'custom.restrict' => \App\Http\Middleware\RestrictMiddleware::class, ];
- Then, apply this middleware to the
/restricted-route
in the routes/api.php file as follows and test:
Route::middleware(['custom.restrict'])->group(function () { Route::get('/restricted-route', [BookController::class, 'getBooks']); });
When working correctly, this middleware blocks all requests from the IPs in the
$restrictedIps
array:127.0.0.1
and102.129.158.0
. Requests from these IPs return a 403 Forbidden response, as shown below:A 403 Forbidden response for the /restricted-route GET endpoint on Postman How To Throttle Requests by IP Address
Next, you rate limit requests using the user’s IP address.
- Apply the Throttle middleware to the
/book
endpoint’sGET
andPATCH
routes in routes/api.php:
Route::middleware(['throttle:minute'])->group(function () { Route::get('/book', [BookController::class, 'getBooks']); }); Route::middleware(['throttle:5,1'])->group(function () { Route::patch('/book', [BookController::class, 'updateBook']); });
- You must also update the
configureRateLimiting
function in the app/Providers/RouteServiceProvider file with the middleware you added to the above routes.
… RateLimiter::for('minute', function (Request $request) { return Limit::perMinute(5)->by($request->ip()); });
This configuration limits requests to the
/book GET
endpoint to 5 per minute, as shown below.A “429 Too Many Requests” response for the /book GET endpoint on Postman. How To Throttle Based on User ID and Sessions
- To rate limit using
user_id
andsession
parameters, update theconfigureRateLimiting
function in the app/Providers/RouteServiceProvider file with the following additional limiters and variables:
... RateLimiter::for('user', function (Request $request) { return Limit::perMinute(10)->by($request->user()?->id ?: $request->ip()); }); RateLimiter::for('session', function (Request $request) { return Limit::perMinute(15)->by($request->session()->get('key') ?: $request->ip()); });
- Finally, apply this code to the
/book/{id} GET
and/book POST
routes in theroutes/api.php
file:
Route::middleware(['throttle:user'])->group(function () { Route::get('/book/{id}', [BookController::class, 'getBook']); }); Route::middleware(['throttle:session'])->group(function () { Route::post('/book', [BookController::class, 'createBook']); });
This code limits requests using
user_id
andsession
, respectively.Additional Methods in Throttle
Laravel Throttle features several additional methods for greater control over your rate-limiting implementation. These methods include:
attempt
— Hits the endpoint, increments the hit count, and returns a boolean indicating whether the configured hit limit has been exceeded.hit
— Hits the Throttle, increments the hit count, and returns$this
to enable another (optional) method call.clear
— Resets the Throttle count to zero and returns$this
so you can make another method call if desired.count
— Returns the total number of hits to the Throttle.check
— Returns a boolean indicating whether the Throttle hit limit has been exceeded.
- To explore rate limiting using these methods, create a middleware app called CustomMiddleware using the command below:
php artisan make:middleware CustomMiddleware
- Then, add the following import files to the newly created middleware file in app/Http/Middleware/CustomMiddleware.php:
use GrahamCampbell\Throttle\Facades\Throttle; use App;
- Next, replace the content of the
handle
method with the following code snippet:
$throttler = Throttle::get($request, 5, 1); Throttle::attempt($request); if(!$throttler->check()){ App::abort(429, 'Too many requests'); } return $next($request);
- In the app/Http/Kernel.php file, create an alias for this middleware app by updating the
middlewareAliases
array as follows.
protected $middlewareAliases = [ . . . 'custom.throttle' => \App\Http\Middleware\CustomMiddleware::class, ];
- Then, apply this middleware to the
/custom-route
in the routes/api.php file:
Route::middleware(['custom.throttle'])->group(function () { Route::get('/custom-route', [BookController::class, 'getBooks']); });
The custom middleware just implemented checks if the throttle limit has been exceeded using the
check
method. If the limit is exceeded, it responds with a 429 error. Otherwise, it allows the request to continue.How To Deploy the Application to the Kinsta Server
Now that you’ve explored how to implement rate limiting in a Laravel application, deploy the app to the Kinsta server to make it accessible globally.
- Start by pushing the updated code to GitHub, GitLab, or Bitbucket.
- From your Kinsta dashboard, click the Add service button and select Application from the list. Link your Git account to your Kinsta account and select the correct repository to deploy.
- Under Basic details, name the application and choose your preferred data center. Also, ensure you added the necessary application environment variables. These correspond to the variables present in your local .env file: the
APP_KEY
and the database configuration variables.
Application details on MyKinsta. - Click the Continue button to select the build environment variables. You can leave the default values, as Kinsta auto-fills the necessary parameters.
- On the Processes tab, you can leave the default values or enter a name for your process. You can also select the pod and instance sizes on this tab.
- Finally, the Payment tab displays a summary of your selections. Add your preferred payment option to finalize the process.
- Once complete, click the Applications tab to view a list of deployed applications.
- Click the application name to view its deployment details, as shown below. You can use the application’s URL to access it.
Deployment details on MyKinsta dashboard. How To Test the Application
- To test the application locally, use the
php artisan serve
command.
This command makes your application browser accessible at
http://localhost:8000
. You can test the API endpoints to which you implemented rate limiting from here by making repeated calls to trigger the rate limit functionality.The Kinsta server displays an Access Forbidden response because you haven’t added configuration details that direct Kinsta on how to serve the application. Add these details now.
- Create a
.htaccess
file in your app’s root directory and add the following code to the file:
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^(.*)$ public/$1 [L] </IfModule>
- Push these changes to GitHub and Kinsta auto-deploys to enact the change.
- Now, open the application using the provided URL and ensure you see the Laravel welcome page.
You can now test the API endpoints to which you implemented rate limiting using Postman by making repeated calls until you’ve reached the configured limit. You receive a 429 Too Many Requests response after exceeding the limit.
Summary
Integrating rate-limiting functionalities into a Laravel API helps control the rate at which users consume an application’s resources. Rate limiting helps you to provide a reliable user experience without under and over-spending. It also ensures the application’s underlying infrastructure remains functional and efficient.
You can also check out the Kinsta blog to learn more about other exciting concepts on Laravel and other web technologies. The affordable and seamless hosting services are highly recommended for your application and team’s needs.
- Then, apply this middleware to the
Leave a Reply