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.
Top comments (5)
I don't see where this
config(['app.api.version' => $guard]);
used??
and why do we need middleware??
Sir Where to add these following code of mapApiRoutes
call it inside
boot
functionAdd them in /app/Providers/RouteServiceProvider.php
Hi!
What's purpose of 'api_latest' => '2' ?