API Versioning in Laravel

While upgrading the functionality of the application sometimes we need to change the majority portion of logic. In common cases doesn’t affect web applications but for APIs, it can be tricky. Some users don’t choose to upgrade the application and they can face errors in using the same APIs. API versioning provides a way to improve their functionality without affecting the client’s application.

There are many ways to implement API versioning in Laravel. Here we will show you the simplest way.

What’s API Versioning?

API versioning is the practice of releasing multiple versions of an Application Programming Interface (API) to support different features and it also provides backward compatibility. It allows developers to update and improve their APIs over time without breaking or affecting users. Often when a new version is published some of the older versions are maintained for some period of time.

The following endpoints will clear your vision about API versioning:

https://www.codewolfy.com/api/v1/users
https://www.codewolfy.com/api/v2/users

Above both URLs are used to get a list of users. While in both endpoints there can be different numbers of data can be available. For example, the first point will only return the email and username of users while the second endpoint will return additional data like registered date, contact number, etc…

Folder or File Structure

In the Folder or file structure, we will segregate files like controllers and routes for different versions so we can use them as per requirement.

For controllers let’s assume we have created an API directory in our Http folder which contains all controllers for APIs. Let’s create sub-folders for API controllers by V1 and V2. For the first version, we will move all existing into the V1 folder and for version 2 we will create a new set of controllers as per the new functionality.

After restructuring, your file structure should look something like this:

/app
  /Http
    /Controllers
      /Api
        /v1
          /UserController.php
        /v2
          /UserController.php

We will perform the same action for routes but instead of creating folders we will create version-wise route files like the below:

routes/api_v1.php
routes/api_v2.php

Handling API Requests By Version

Before starting let’s specify the latest version in our configuration so that whenever the client request doesn’t have any specific version then we will provide a response with the latest version. To do that open the config/app.php file and add the following:

/*
Latest API Version
*/

'api_latest'  => '2',

To handle requests by the client-specified version we have to apply a filter on requests and for that we will use the Laravel middleware. Open the terminal and enter the below command:

php artisan make:middleware APIVersion

Once middleware is created, we will apply logic for versioning.

<?php
namespace App\Http\Middleware;

use Closure;

class APIVersion
{
    /**
     * Handle an incoming request.
     *
     * @param  Request $request
     * @param  Closure $next
     *
     * @return mixed
     */
    public function handle($request, Closure $next, $guard)
    {
        config(['app.api.version' => $guard]);
        return $next($request);
    }
}

We have to register it on your app/Http/Kernel.php file:

protected $routeMiddleware = [
    ...
    ...
    'api_version' => App\Http\Middleware\APIversion::class,
];

Open the file app/Providers/RouteServiceProvider.php and add modify as below:

<?php

namespace App\Providers;

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;

class RouteServiceProvider extends ServiceProvider
{
    protected $apiNamespace ='App\Http\Controllers\Api';

    public const HOME = '/home';

    public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::group([
                'middleware' => ['api', 'api_version:v1'],
                'namespace'  => "{$this->apiNamespace}\V1",
                'prefix'     => 'api/v1',
            ], function ($router) {
                require base_path('routes/api_v1.php');
            });
        
            Route::group([
                'middleware' => ['api', 'api_version:v2'],
                'namespace'  => "{$this->apiNamespace}\V2",
                'prefix'     => 'api/v2',
            ], function ($router) {
                require base_path('routes/api_v2.php');
            });

            Route::middleware('web')
                ->group(base_path('routes/web.php'));

            Route::prefix('admin/')
                ->as('admin.')
                ->middleware('web')
                ->group(base_path('routes/admin.php'));
        });
    }

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

Now we have configured versioning. so whenever we need to create a new version just need to create new controllers, route files, and config new route files in a route service provider.

Conclusion

In this post, we have created API versioning and a really simple way to implement it in our Laravel applications.