Урок 10

Версионирование API

Когда API меняется, старые клиенты ломаются. Версионирование позволяет выпускать новые версии, не затрагивая существующих клиентов.

Стратегии

  • URL-версия — /api/v1/posts, /api/v2/posts
  • Заголовок — Accept: application/vnd.api.v1+json
  • Query-параметр — /api/posts?version=1

URL-версия самая простая и явная. Laravel хорошо поддерживает её через префиксы.

Реализация через префикс

Route::prefix('v1')->group(function () {
    Route::apiResource('posts', V1\PostController::class);
});

Route::prefix('v2')->group(function () {
    Route::apiResource('posts', V2\PostController::class);
});

URL: /api/v1/posts и /api/v2/posts.

Отдельные контроллеры

app/Http/Controllers/Api/V1/PostController.php
app/Http/Controllers/Api/V2/PostController.php

Разные версии могут возвращать разные поля, использовать разные правила валидации.

Отдельные ресурсы

app/Http/Resources/V1/PostResource.php
app/Http/Resources/V2/PostResource.php

V2 может добавить поля, изменить структуру.

Отдельные роут-файлы

routes/api.php
routes/api_v1.php
routes/api_v2.php

Регистрация в bootstrap/app.php:

->withRouting(
    web: __DIR__.'/../routes/web.php',
    api: __DIR__.'/../routes/api.php',
    commands: __DIR__.'/../routes/console.php',
    then: function () {
        Route::middleware('api')
            ->prefix('api/v1')
            ->group(base_path('routes/api_v1.php'));

        Route::middleware('api')
            ->prefix('api/v2')
            ->group(base_path('routes/api_v2.php'));
    },
)

Депрекация

Когда старая версия больше не нужна:

  1. Помечаешь её как deprecated в документации
  2. Возвращаешь заголовок Deprecation: true
  3. Через несколько релизов удаляешь
return response()->json($data)
    ->header('Deprecation', 'true')
    ->header('Sunset', '2027-01-01');

Итоги

  • Используй URL-версию для явности
  • Отдельные контроллеры и ресурсы на каждую версию
  • Не ломай старые версии — выпускай новые
  • Предупреждай о депрекации заранее