Laravel 8 - API Versioning ⭐⭐⭐⭐⭐
Tags: php, laravel, api, bestpractices
Published: 2022-02-13 11:50:43

**What is “API Versioning”?**

**API versioning** is the process of creating new versions of an API whenever some big changes is necessary that could break the existing version of the API and ruin all the sites, apps or systems connected to it.

> It has become very common in recent years, the main idea behind API versions is to never delete the old versions of our code, whenever we need to make big changes in our system, specifically when this changes could create problems with integrations (Softwares who are consuming our APIs). 

Following this idea we will have endpoints like this:

```
https://www.website.com/api/v1/users
https://www.website.com/api/v2/users
```

Note that the difference between the endpoints is “v1” and “v2”, they are related to the version we are using. 

> By implementing it this way, the old integrations (apps, external Softwares, Front-end applications,…) could keep using the first version (v1) while the new version integrations could just use version 2 (v2). 

Following this principle, we do not have worry about updates or new features breaking our clients integrations.

**How to apply versioning to folder?**

The first thing to do is to organize the folders. 

Create a folder called Api inside `app/Http/Controllers`, then create two folders called V1 and V2 inside `app/Http/Controllers/Api`, you should have something like this:

```
app/Http/Controllers/Api/V1
app/Http/Controllers/Api/V2
```
it will look like this

 

```
/app
  /controllers
    /Api
      /v1
        /UserController.php
      /v2
        /UserController.php
```

Create controllers for v1 version:
`php artisan make:controller Api/V1/MyController`

Create jsonResource for v1 version
`php artisan make:resource V1/UserResource`

Example how to create jsonResource for v2 version
`php artisan make:resource V2/UserResource`

The idea is that each controller uses a different resource, the first controller version should look like this:
```
<?php
namespace App\Http\Controllers\Api\V1;

use App\Models\User;

class UserController
{
    public function getUser(int $idUser)
    {
        $user = User::find($idUser);

        return new \App\Http\Resources\V1\User($user);
    }
}
```

In the second version, we just need to use a different resource. The same idea could be replicated for Models, Views, Services, Repositories, or whatever layer you could be using.

 
**Load Controller according to the version (URL)**

To do that we will use the Laravel middleware. 

First of all, open the file config/app.php in your favorite editor, add the following lines of code:

```
/*
|-------------------------------------------
| Current API Version
|-------------------------------------------
*/

'api_latest'  => '2',
```

Now, we need to create our middleware, execute the following command on your terminal:
`php artisan make:middleware APIVersion`

Open the middleware created (`app\Http\Middleware\APIVersion.php`) and add the code:

```
<?php
namespace App\Http\Middleware;use Closure;

/**
 * Class APIVersion
 * @package App\Http\Middleware
 */
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);
    }
}
```

This middleware will be responsible for intercepting the `requests` and apply the version requested by the clients.

Don't forget 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 this attribute to the class:

```
/** @var string $apiNamespace */
protected $apiNamespace ='App\Http\Controllers\Api';
```

Inside the method `mapApiRoutes`, add the following code:

```
/**
 * Define the "api" routes for the application.
 *
 * These routes are typically stateless.
 *
 * @return void
 */
protected function mapApiRoutes()
{
    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');
    });
}
```

In that way, we will separate the route groups in different files, look closely! we are using the PHP method `require` to load:

```
routes/api_v1.php
routes/api_v2.php
```

It will be necessary to create two different files manually after you just need to follow the same idea on the file `routes/api.php`created by Laravel on the setup of new projects.

The original file will not be necessary since now. It keeps the routes more organized when your project grows. After that, you just need to create your controllers and routes.

> Hurray! you learned how to keep your **APIs/projects** more organized, mainly thinking about the future of your application.