Setting Up API Call Limits In Laravel - Part 1

Setting Up API Call Limits In Laravel - Part 1

In this two part series of articles, I'll go through two ways to set up a request limit for your API based on the calling user's access level. This is extremely useful for any subscription-based API where you want to limit user groups to a specific number of API calls per a certain amount of time.

This part is going to be focused on using Laravel's built in Rate limiters, the second one will dive into creating a custom middleware to enforce the set limits.

Using a Rate Limiter

The simplest way to achieve this goal is to set up a rate limiting service which is built into Laravel and enabled by default for API middleware-restriced routes. The default limit is set to 60 requests per minute. The configuration can be changed in /app/Providers/RouteServiceProvider in the ConfigureRateLimiting() method. This is the default:

protected function configureRateLimiting()
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60);
    });
}

If you wanted to disable the default limit (which I wouldn't recommend as you would allow users to make unlimited requests to your API endpoints which may lead to overloads), you may do return Limit::none(); in this function, or you could remove this throttle from the api middleware group in /app/Http/Kernel.

Defining a custom rate limiter

In the configureRateLimiting() method, you can define more rate limiters. Let's make a limiter called matches which is going to limit calls to API route for fetching results from various football matches.

For this use case, let's say we have 3 types of users, an unregistered visitor, a registered user with a free account and a registered user who has subscribed to our service. The first one isn't registered, thus doesn't have an API token, therefore they cannot access our API, the second one has an API access token, but their request limit is one request per hour, the subscribed user has unlimited calls. We will be using the following variables:

  • Access Level - Category the user belongs to, 0 is a free account user, 1 is a subscribed user. This is represented by the access column in the database
  • Bearer Token - Unique API token type for request authentication which is represented by the api_token column in the database

Now let's put it all together.

//RouteServiceProvider.php
protected function configureRateLimiting()
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60);
    });

    RateLimiter::for('matches', function (Request $request) {
      $user = User::where('api_token', $request->bearerToken())
              ->first();
      switch ($user->access) {
        case 0:
          return Limit::perHour(1)->response(function () {
            return response()->json(
              ['error' => 'Request limit exceeded'],
              429
            );
          });
          break;
        case 1:
          return Limit::none();
          break;
      }
    });
}
//routes/api.php
Route::middleware(['auth:api','json.force','throttle:matches'])
->get('test', 'ApiController@testMatches');

Now that we have successfully set our own limit, we can disable the original api rate limiter, as our subscribed users would still be limited by it, as you can see below.

api_test.gif

The script used for testing the API can be found here

To achieve this, we can simply set the API rate limiter to no limit, alternatively, we could disable the throttle:api in the api middleware group in /app/Http/Kernel altogether.

Next up

Next time, I will be showing you how I tackled the request rate limiting problem myself the first time I encountered the need to limit the access to my API. This option is a little bit more tricky than the one I've shown you today, as it involves creating a set of custom middleware and working with the database a little more.

To be continued...

Did you find this article valuable?

Support Dominik Zarsky by becoming a sponsor. Any amount is appreciated!