PHP code example of jayanta / laravel-api-versionist

1. Go to this page and download the library: Download jayanta/laravel-api-versionist library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

jayanta / laravel-api-versionist example snippets


// Your controller. Always latest version. That's it.
class UserController extends Controller
{
    public function show(User $user)
    {
        return response()->json([
            'handle' => $user->handle,
            'roles' => $user->roles,
        ]);
    }
}

// app/Api/Transformers/V2Transformer.php

final class V2Transformer extends ApiVersionTransformer
{
    public function version(): string { return 'v2'; }

    public function description(): string
    {
        return 'Renamed username to handle, converted role string to roles array.';
    }

    public function upgradeRequest(array $data): array
    {
        if (isset($data['username'])) {
            $data['handle'] = $data['username'];
            unset($data['username']);
        }

        if (isset($data['role']) && is_string($data['role'])) {
            $data['roles'] = [$data['role']];
            unset($data['role']);
        }

        return $data;
    }

    public function downgradeResponse(array $data): array
    {
        if (isset($data['handle'])) {
            $data['username'] = $data['handle'];
            unset($data['handle']);
        }

        if (isset($data['roles']) && is_array($data['roles'])) {
            $data['role'] = $data['roles'][0] ?? 'user';
            unset($data['roles']);
        }

        return $data;
    }
}

// config/api-versionist.php
'latest_version' => 'v2',
'transformers' => [
    App\Api\Transformers\V2Transformer::class,
],
'response_data_key' => null, // null for flat JSON, 'data' for wrapped responses

// routes/api.php
Route::middleware('api.version')->group(function () {
    Route::get('/users/{user}', [UserController::class, 'show']);
});

// or use the shorthand macro
Route::versioned()->group(function () { /* ... */ });

final class V2Transformer extends ApiVersionTransformer
{
    public function version(): string { return 'v2'; }
    public function description(): string { return 'Renamed username to handle, role string to roles array.'; }
    public function releasedAt(): ?string { return '2025-03-01'; }

    public function upgradeRequest(array $data): array
    {
        if (isset($data['username'])) {
            $data['handle'] = $data['username'];
            unset($data['username']);
        }

        if (isset($data['role']) && is_string($data['role'])) {
            $data['roles'] = [$data['role']];
            unset($data['role']);
        }

        return $data;
    }

    public function downgradeResponse(array $data): array
    {
        if (isset($data['handle'])) {
            $data['username'] = $data['handle'];
            unset($data['handle']);
        }

        if (isset($data['roles']) && is_array($data['roles'])) {
            $data['role'] = $data['roles'][0] ?? 'user';
            unset($data['roles']);
        }

        return $data;
    }
}

use Versionist\ApiVersionist\Attributes\ApiVersion;

#[ApiVersion('v2', description: 'Renamed username to handle.', releasedAt: '2025-03-01')]
final class V2Transformer extends ApiVersionTransformer
{
    public function upgradeRequest(array $data): array { /* ... */ }
    public function downgradeResponse(array $data): array { /* ... */ }
}

final class V3Transformer extends ApiVersionTransformer
{
    public function __construct(
        private readonly UserRepository $repo
    ) {}

    public function version(): string { return 'v3'; }
    public function description(): string { return 'Added legacy_role lookup for v2 clients.'; }

    public function downgradeResponse(array $data): array
    {
        if (isset($data['user_id'])) {
            $data['legacy_role'] = $this->repo->getLegacyRole($data['user_id']);
        }
        return $data;
    }
}

if ($request->isApiVersionAtLeast('v3')) {
    // new pricing logic, auth behavior, business rules
}

'detection_strategies' => ['url_prefix', 'header', 'query_param'],

'deprecated_versions' => [
    'v1' => '2025-12-31',
    'v2' => null,  // deprecated, no sunset date yet
],

'rfc_compliant_headers' => true,

'deprecated_versions' => [
    'v1' => ['deprecated_at' => '2025-01-01', 'sunset' => '2025-06-01'],
],

'changelog' => [
    'enabled'    => true,
    'endpoint'   => '/api/versions',
    'middleware' => ['api'],
],

$request->apiVersion();              // "v2"
$request->isApiVersion('v2');        // true
$request->isApiVersionAtLeast('v2'); // true for v2, v3, v4...
$request->isApiVersionBefore('v3');  // true for v1, v2

if ($request->isApiVersionAtLeast('v3')) {
    $users->each(fn ($user) => $user->append('login_streak'));
}

'response_data_key' => 'data',
'request_data_key' => 'data',

class V2TransformerTest extends TestCase
{
    private V2Transformer $transformer;

    protected function setUp(): void
    {
        $this->transformer = new V2Transformer();
    }

    public function test_upgrade_renames_username_to_handle(): void
    {
        $result = $this->transformer->upgradeRequest([
            'username' => 'janedoe',
            'role' => 'admin',
        ]);

        $this->assertSame('janedoe', $result['handle']);
        $this->assertSame(['admin'], $result['roles']);
        $this->assertArrayNotHasKey('username', $result);
    }

    public function test_round_trip_preserves_data(): void
    {
        $original = ['username' => 'janedoe', 'role' => 'admin'];
        $upgraded = $this->transformer->upgradeRequest($original);
        $downgraded = $this->transformer->downgradeResponse($upgraded);

        $this->assertSame($original, $downgraded);
    }
}

public function test_v3_downgrade_adds_legacy_role(): void
{
    $repo = $this->createMock(UserRepository::class);
    $repo->method('getLegacyRole')->with(42)->willReturn('editor');

    $transformer = new V3Transformer($repo);

    $result = $transformer->downgradeResponse(['user_id' => 42, 'handle' => 'jane']);
    $this->assertSame('editor', $result['legacy_role']);
}
bash
php artisan api:make-transformer v2

Deprecation: true
Sunset: 2025-12-31
Link: </api/versions>; rel="successor-version"

Deprecation: @1735689600                       ← RFC 9745 (unix timestamp)
Sunset: Sun, 01 Jun 2025 00:00:00 GMT          ← RFC 8594 (HTTP-date)