This post shows how to quickly build a very simple middleware to add a rate limit to selected routes in a Laravel application. It makes use of Laravel’s build in caching system to store the users request count, the time to reset and returns all the necessary information to the users via http response headers, as well as handling exceeded rate limit messages.
The middleware code below makes use of three different parameters which will be factors of the rate limit.
- Time Period - set the time period, the period of time in which the rate limit it enforced.
- Limit Number of Requests - set the maximum number of requests, this is the total number of requests which can be made during the given time period.
- Cost of the Request - set a cost value relating to the api request, for example you may have an API endpoint which is process heavy and you may wish to place an addition weight to the requests above the default value.
We need to provide API consumers information of their current rate limits, one common practice is to provide additional HTTP headers in the response and depending on the application and personal preference there are a number of different HTTP headers which can be returned to assist API consumers.
There are lots of blog posts, examples and suggested standards. Below is a list some of the commonly implemented responses headers, at the end of the day it’s your decision as to how you inform your uses just remember to document it clearly within your API documentation.
|X-RateLimit-Cost||The cost of the request used as part of the request.|
|X-RateLimit-Limit||The maximum number of requests that the consumer is permitted to make per hour.|
|X-RateLimit-Remaining||The number of requests remaining in the current rate limit window.|
|X-RateLimit-Reset||The time at which the current rate limit window resets in UTC epoch seconds.|
|X-RateLimit-Reset-Ttl||The time-to-live until the current rate limit window resets in seconds.|
For more information and real world examples take a look at someone else’s API for inspiration.
- GitHub https://developer.github.com/v3/#rate-limiting
- Twitter https://dev.twitter.com/rest/public/rate-limiting
Laravel has built-in support for many caching drivers which we can make use of, by default Laravel is setup to use the file system as its cache storage which is fine for small applications. However this isn’t really practical for a real applications for many reasons, if you want to understand more about the benefits and disadvantages to each caching driver just do some searching around I’m sure there are lots of opinions but in the end it comes down to your application and the potential scale of your project.
If your using Laravel homestead as your local development environment you have both redis and memcached installed and ready to use, just set the cache driver in your ‘.env’ file and your good to go. Check out the documentation for configuring laravel’s caching drivers for more information.
Building the Rate-Limit Middleware
There are two options for setting up the new middleware we can use the artisan generator to generate the initial template or you can simply copy the below code and add the file to the middleware folder in your project directory.
Here is the full source for the middleware class which provides the rate limiting and sets up the response headers to be return, depending on your given preferences you may wish to change the error messages and/or the types of headers returned in the response.
Next update /app/Http/Kernel.php adding the following instruction which will make Laravel aware of the new custom middleware:
To wrap things up, just apply the middleware to your routes as required:
Optionally add custom limit and cost values, they can be specified as middleware parameters.