Урок 02

Настройка API в Laravel

Установка

Одна команда — всё сразу:

php artisan install:api

Что делает:

  1. Создаёт routes/api.php.
  2. Регистрирует его в bootstrap/app.php.
  3. Устанавливает Sanctum через Composer.
  4. Создаёт миграцию personal_access_tokens.
  5. Предлагает запустить migrate.
php artisan migrate

Что появилось

routes/api.php:

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

Миграция personal_access_tokens — таблица для токенов.

В config/sanctum.php — настройки.

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

Если ставил вручную:

->withRouting(
    web: __DIR__.'/../routes/web.php',
    api: __DIR__.'/../routes/api.php',
    commands: __DIR__.'/../routes/console.php',
    health: '/up',
)

Префикс /api

По умолчанию — /api.

Изменить:

->withRouting(
    api: __DIR__.'/../routes/api.php',
    apiPrefix: 'api/v1',
)

Теперь все роуты из api.php получат префикс /api/v1.

Или через группу:

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

Middleware

Группа api по умолчанию:

->withMiddleware(function (Middleware $middleware) {
    $middleware->api(prepend: [
        // свои middleware в начало группы api
    ]);
})

Что применяется:

  • throttle:api — 60 запросов в минуту.
  • SubstituteBindings — Route Model Binding.

Чего НЕТ:

  • Сессий (StartSession).
  • CSRF (VerifyCsrfToken).
  • Cookie шифрования.

Причина: API — stateless.

Формат ответа

Laravel возвращает JSON, если:

  • Клиент прислал Accept: application/json.
  • Роут из api.php.
  • Возвращается массив / JsonResource / объект.
Route::get('/posts', function () {
    return Post::all();
});

Вернёт:

[
    { "id": 1, "title": "...", "body": "..." },
    { "id": 2, "title": "...", "body": "..." }
]

Ошибки

Валидация:

{
    "message": "The title field is required.",
    "errors": {
        "title": ["The title field is required."]
    }
}

404:

{
    "message": "No query results for model [App\\Models\\Post] 5"
}

500:

{
    "message": "Server Error"
}

Что показывать — зависит от APP_DEBUG. На проде — общие сообщения.

CORS

Cross-Origin Resource Sharing — если фронт на другом домене.

config/cors.php:

return [
    'paths' => ['api/*', 'sanctum/csrf-cookie'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['https://app.example.com'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => false,
];

supports_credentials: true — если нужны cookies (Sanctum для SPA).

Для разработки:

'allowed_origins' => ['http://localhost:3000', 'http://localhost:5173'],

Два варианта API

Токены (мобильные, внешние)

Authorization: Bearer <token>

Плюс: работает в любом клиенте.

Cookies (SPA)

CSRF-token + cookies.

Плюс: безопаснее, httpOnly cookies.

Минус: нужен CSRF, CORS с credentials.

Установка вручную (без install:api)

composer require laravel/sanctum.

bootstrap/app.php:

->withRouting(
    api: __DIR__.'/../routes/api.php',
)

Миграция:

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

В User:

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens;
}

Практика

Установи API в свой проект:

php artisan install:api
php artisan migrate

Добавь тестовый роут:

// routes/api.php
Route::get('/ping', fn () => ['status' => 'ok']);

Проверь через curl:

curl http://localhost:8000/api/ping
# {"status":"ok"}

С заголовком Accept:

curl -H "Accept: application/json" http://localhost:8000/api/ping

Проверь CORS:

curl -H "Origin: http://localhost:3000" -v http://localhost:8000/api/ping
# Смотри Access-Control-Allow-Origin

Частые ошибки

1. Забыли php artisan migrate:

SQLSTATE: relation "personal_access_tokens" does not exist

2. Не тот префикс:

Route /ping не найден — проверь /api/ping

3. Не установлен use HasApiTokens:

$user->createToken('auth');   // Error: Call to undefined method

4. CORS не работает:

Access to fetch at 'http://api.example.com' from origin 'http://app.example.com' has been blocked

Решение: добавить origin в config/cors.php.

5. Сессии не работают:

session(['key' => 'value']);   // не сохранится

Причина: API без сессий. Используй токены.

Итог

  • php artisan install:api — установка в одну команду.
  • routes/api.php — префикс /api.
  • Middleware api — без сессий, throttle.
  • JSON — по умолчанию для api.php.
  • CORS — config/cors.php.
  • Токены или cookies — два варианта.
  • Не забывай migrate после установки.

Дальше — API-ресурсы.