Cara, usa Laravel. Você pode criar agrupar as rotas com prefix e name e só criar diretórios diferentes para cada versão, e manter os mesmo nomes das classes, só que em namespaces diferentes, não tem complicação nenhuma.

// Dentro do arquivo routes/api.php

// importação da rota v1
use App\Http\Controllers\Api\V1\ProdutoController;
use App\Http\Controllers\Api\V2\ProdutoController as ProdutoControllerV2; // alias por ter o mesmo nome da classe acima

// versão 1
Route::prefix('v1')->name('v1.')->group(function(){
 // exemplo de rota de produtos
 Route::apiResource('produtos', ProductController::class); // (dominio.com.br/api/v1/produtos) - rota interna (api.v1.produtos)
});


// versão 2
Route::prefix('v2')->name('v2.')->group(function(){
 // exemplo de rota de produtos
 Route::apiResource('produtos', ProductController::class); // (dominio.com.br/api/v2/produtos) - rota interna (api.v2.produtos)
});

Se quiser deixar mais organizado ainda, você pode separa os arquivos de rotas por versão e daí nem precisa fazer o alias. Dentro do seu diretório ficaria assim:

  • /routes/api.php
  • /routes/api/v1.php
  • /routes/api/v2.php

Aí no arquivo/routes/api.php

    // versão 1
    require __DIR__ . '/api/v1.php';
    // versão 2
    require __DIR__ . '/api/v2.php';

Dentro da v1, por exemplo:

// importação da rota v1
use App\Http\Controllers\Api\V1\ProdutoController;

// versão 1
Route::prefix('v1')->name('v1.')->group(function(){
 // exemplo de rota de produtos
 Route::apiResource('produtos', ProductController::class); // (dominio.com.br/api/v1/produtos) - rota interna (api.v1.produtos)
});

Dentro da v2, por exemplo:

// importação da rota v2
use App\Http\Controllers\Api\V2\ProdutoController;

// versão 2
Route::prefix('v2')->name('v2.')->group(function(){
 // exemplo de rota de produtos
 Route::apiResource('produtos', ProductController::class); // (dominio.com.br/api/v2/produtos) - rota interna (api.v2.produtos)
});