Глава 2.5: Маршруты API
Время изучения: 45 минут
1. Что такое маршрут? Объяснение на пальцах
Представьте, что ваш контроллер (PlanetController
) — это большой офисный центр, а каждый его метод (index
, store
, show
) — это отдел, выполняющий свою работу.
Маршрут (Route) — это адресная табличка на входе в здание. Она говорит:
- "Если кто-то пришел по адресу
/planets
методом GET — отправьте его в отделindex
(показать всё)". - "Если кто-то пришел по адресу
/planets
методом POST с посылкой (данными) — отправьте его в отделstore
(создать новое)".
Без маршрутов ни один запрос из внешнего мира не найдет нужный ему отдел в вашем коде. Основной файл для таких "адресных табличек" в API — это routes/api.php
.
В Laravel 11+ по умолчанию нет "API-адресной книги". Мы создали ее сами, выполнив команду php artisan install:api. Теперь у нас есть файл routes/api.php — это главный центр управления всеми маршрутами нашего API.
Ключевое отличие api.php от web.php:
- Префикс /api: Laravel автоматически добавляет /api ко всем URL-адресам из этого файла. Маршрут /planets превращается в /api/planets.
- "Без состояния" (Stateless): Здесь нет сессий и cookie-файлов, как в обычном вебе. Каждый запрос независим и должен содержать в себе всю информацию для аутентификации (обычно это API-токен в заголовках).
2. Путь новичка: Создание маршрута вручную
Давайте создадим один-единственный маршрут своими руками, чтобы понять принцип. Наша цель — заставить URL /api/planets
показывать список всех планет.
Откройте routes/api.php
и напишите:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PlanetController; // Указываем, где наш контроллер
// (1) (2) (3)
Route::get( '/planets', [PlanetController::class, 'index'] );
// ^ ^ ^
// (HTTP-метод) (URL-адрес) (Какой контроллер и метод вызвать)
Разберем эту строку по частям:
Route::get(...)
— мы говорим: "Этот маршрут работает только для GET-запросов".'/planets'
— это URL, который будет слушать Laravel. С учетом префикса/api
, полный адрес будетhttp://space-api.test/api/planets
.[PlanetController::class, 'index']
— это "пункт назначения". Мы говорим: "Когда запрос придет, найди классPlanetController
и вызови в нем методindex()
".
Теперь всё связано! Запрос -> Маршрут -> Контроллер -> Метод.
А что, если нам нужно получить одну планету по ее ID? Например, /api/planets/5
.
// Маршрут для получения конкретной планеты
Route::get('/planets/{planet}', [PlanetController::class, 'show']);
Здесь {planet}
— это "шаблон" или переменная. Laravel понимает, что на этом месте может быть что угодно (ID, слаг). Затем он передает это значение в метод show(Planet $planet)
. Эта "магия", когда Laravel сам находит планету по ID, называется Route Model Binding.
3. Путь мастера: apiResource
— одна строка, чтобы править всеми
Создавать каждый маршрут вручную (для index
, show
, store
, update
, destroy
) утомительно. Разработчики Laravel это понимают, поэтому создали мощный помощник — apiResource
.
Удалите все, что мы написали, и замените одной строкой:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PlanetController;
Route::apiResource('planets', PlanetController::class);
Что эта одна строка делает под капотом? Она автоматически создает целый набор маршрутов для стандартных CRUD-операций, которые мы уже реализовали в контроллере.
Метод | URL | Направляется в метод | Назначение |
---|---|---|---|
GET | /api/planets |
index() |
Получить список всех планет |
POST | /api/planets |
store() |
Создать новую планету |
GET | /api/planets/{planet} |
show() |
Показать одну конкретную планету |
PUT/PATCH | /api/planets/{planet} |
update() |
Обновить существующую планету |
DELETE | /api/planets/{planet} |
destroy() |
Удалить планету |
Вы можете убедиться в этом сами. Выполните в терминале команду:
Вы увидите таблицу со всеми созданными маршрутами. apiResource
— это ваш лучший друг для экономии времени при создании стандартных API.
4. Специальные миссии и порядок маршрутов
Что если нам нужен нестандартный маршрут, которого нет в apiResource
? Например, получить случайную планету по адресу /api/planets/random
.
Давайте добавим его. Но здесь есть смертельно важная ловушка, в которую попадают 9 из 10 новичков.
Неправильный порядок (НЕ РАБОТАЕТ!):
Route::apiResource('planets', PlanetController::class);
Route::get('/planets/random', [PlanetController::class, 'random']); // <-- НЕ СРАБОТАЕТ
Route::apiResource
, который создал маршрут GET /planets/{planet}
. Когда вы запросите /planets/random
, Laravel подумает, что "random" — это ID планеты, и попытается найти в базе данных планету с ID "random" и вы получите ошибку.
Правильный порядок (РАБОТАЕТ!):
<?php
use App\Http\Controllers\PlanetController;
use Illuminate\Support\Facades\Route;
// 1. Сначала объявляем КОНКРЕТНЫЕ маршруты
Route::get('/planets/random', [PlanetController::class, 'random']);
// 2. И только потом объявляем ОБЩИЕ маршруты с переменными
Route::apiResource('planets', PlanetController::class);
⚠️ Важно!
Чтобы проверить маршрут api/planets/random, нужно добавить новый обработчик в PlanetController:
Правило: Всегда объявляйте более конкретные маршруты (такие как /random
) перед более общими и шаблонными маршрутами (такими как /{planet}
).
5. Группировка: Наводим порядок
Когда маршрутов становится много, их можно и нужно группировать.
A. Версионирование API
Чтобы в будущем не сломать старые приложения, которые используют ваше API, принято добавлять версию в URL, например /api/v1/...
.
<?php
Route::prefix('v1')->group(function () {
// Все маршруты внутри этой группы получат префикс /v1
// Итоговый URL: /api/v1/planets
Route::get('/planets/random', [PlanetController::class, 'random']);
Route::apiResource('planets', PlanetController::class);
});
B. Защита маршрутов (Middleware) Представим, что смотреть планеты могут все, а вот создавать, обновлять и удалять — только авторизованные пользователи.
<?php
// Публичные маршруты, доступные всем
Route::get('/planets', [PlanetController::class, 'index']);
Route::get('/planets/{planet}', [PlanetController::class, 'show']);
// Группа маршрутов, требующая "пропуска" (аутентификации)
Route::middleware('auth:sanctum')->group(function () {
Route::post('/planets', [PlanetController::class, 'store']);
Route::put('/planets/{planet}', [PlanetController::class, 'update']);
Route::delete('/planets/{planet}', [PlanetController::class, 'destroy']);
});
Здесь middleware('auth:sanctum')
— это как охранник, который проверяет "пропуск" у каждого, кто пытается получить доступ к маршрутам внутри группы.
6. Тестирование через Postman
Теперь, когда все маршруты проложены, пора их проверить.
- Если используете Herd: Ваш сайт уже работает по адресу типа
http://space-api.test
. - Если нет: Запустите локальный сервер командой
php artisan serve
. Адрес будетhttp://localhost:8000
.
Откройте Postman и отправьте запросы:
GET http://space-api.test/api/planets
GET http://space-api.test/api/planets/random
POST http://space-api.test/api/planets
(не забудьте добавить JSON-тело запроса на вкладкеBody
->raw
->JSON
).
Пример POST-запроса:
{
"name": "Kepler-186f",
"description": "Первая планета земного размера в обитаемой зоне",
"size_km": 15000,
"solar_system": "Kepler-186",
"is_habitable": true
}
8. Частые ошибки маршрутизации
- 404 Not Found
- Неправильный URL (
/api/planet
вместо/api/planets
) - Забыли
php artisan serve
- Неправильный URL (
- 405 Method Not Allowed
- Неверный HTTP-метод (например, GET вместо POST)
- Missing Controller
- Опечатка в имени контроллера (
PlanetControler
)
- Опечатка в имени контроллера (
- Route Name Collision
- Повторяющиеся имена маршрутов
Квиз для закрепления
🚀 Итог главы:
Вы построили "гиперпространственные маршруты" для космического API! Теперь:
- 🗺️ Все эндпоинты доступны по
/api/...
- 🔗 Ресурсные маршруты подключены к контроллеру
- 🛡️ Добавлены кастомные маршруты для специальных операций
- ✅ Маршруты протестированы через Postman
Вселенная открыта для запросов! Далее мы добавим защиту от "космического мусора" — валидацию данных.
📌 Проверка:
- Выполните
php artisan route:list
- Убедитесь, что видите 5+ маршрутов для planets
- Проверьте работу GET /api/planets в браузере/Postman
⚠️ Если ошибка 404:
- Проверьте наличие
Route::apiResource
вroutes/api.php
- Убедитесь, что сервер запущен (
php artisan serve
)- Для Windows: разрешите порт 8000 в брандмауэре