Reputation: 361
Since I want to fire endpoints upon accept header, I created a middleware to identify which version is using the client:
// ApiVersionMiddleware
public function handle($request, Closure $next)
{
$route = $request->route();
$actions = $route->getAction();
$actions['uses'] = str_replace(
'{api}',
$request->header('api-version'),
$actions['uses']
);
$route->setAction($actions);
return $next($request);
}
I then changed the default RouteServiceProvider
namespace:
class RouteServiceProvider extends ServiceProvider {
// protected $namespace = 'App\Http\Controllers'; // default value
protected $namespace = null;
.
.
}
Finally, in my routes.php
file, I have:
Route::group(['middleware' => 'api-version'], function()
{
Route::resource('items', 'App\Http\Controllers\{api}\ItemsController', ['only' => ['show', 'index', 'store', 'destroy']]);
});
I tried to register the middleware in the HttpKernel class instead of grouping route definitions but it did not work.
I was wondering if there is a better way to achieve API versioning.
routes.php
file for each version: v1-routes.php
, v2-routes.php
and so on.routes.php
just to get access to the {api}
value. Is any other way to find out which Controller should I fire?Thanks.
Upvotes: 5
Views: 3526
Reputation: 51
For anyone who just want some simple code. This is inside the default RouteServiceProvider. Just add a few lines.
$this->routes(function () {
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
$max_api_version = 6; // how many files should be loaded
$all_headers = getallheaders(); // request object is not available. use php function
$client_version = intval($all_headers['Api-Version']??1);
for ($i = 1; $i <= $max_api_version; $i++){
$file_path = base_path('routes/api_v'.$i.'.php');
if ($client_version >= $i && file_exists($file_path)){
Route::prefix('api')
->group($file_path);
}
}
});
You can't have two identical route in laravel. Laravel will use $method.$domain.$uri
to determine same routes and later ones will simply override previous ones. So loading different version routes in ascending order with the above code will result in:
Upvotes: 0
Reputation: 3971
I guess you can try something like this on your routes.php I haven't tested but should work
switch (Request::header('api-version')) {
case 'v2':
include_once('routes_v2.php');
break;
default:
include_once('routes_v1.php');
}
And in the route_v....php files define the routes as you would do normally.
The correct way to do this would be in the RouteServiceProvider's map function. You will have just two route files.
You can easily manage multiple versions of apis in the dingo/api package. It will save a lot of time for you.
Upvotes: 5