Разработка · 5 мин чтения

Как разработать REST API на Laravel для мобильного приложения

REST API на Laravel для мобильного приложения я делаю чаще всего под связку iOS/Android или Flutter/React Native на фронте, и это одна из самых благодарных задач в бэкенд-разработке - фреймворк даёт готовую инфраструктуру для аутентификации, валидации и работы с базой, а мне остаётся спроектировать эндпоинты под конкретный кейс. За последние пару лет я собрал больше десятка таких бэкендов - от простого MVP на 15 роутов до сервиса с оплатой через эквайринг Т‑Банка и трекингом доставки СДЭК, и в этой статье разберу, как выстраиваю такой API от каркаса до продакшена.

Почему для мобильного бэкенда беру именно Laravel

Мобильному приложению бэкенд нужен предсказуемый - без сюрпризов с сериализацией дат и без ручного написания мидлвара для каждой мелочи. В Laravel из коробки есть Eloquent ORM, миграции, очереди, кэш и Sanctum для токенной аутентификации - это закрывает большую часть типовых задач мобильного API без сторонних пакетов.

На практике сравниваю это с голым Node/Express: там ту же связку валидации, ORM и токенов приходится собирать руками из трёх-четырёх библиотек и следить, чтобы они не конфликтовали между собой. В Laravel всё это уже подружено и обновляется синхронно с релизами фреймворка.

Ещё один довод - Artisan. Генерация контроллеров, ресурсов, форм-реквестов и миграций одной командой экономит день-два на каждом проекте, особенно когда API растёт до 40-50 эндпоинтов.

Как проектирую структуру REST API на Laravel

Начинаю всегда с routes/api.php и группировки по версиям - даже если мобильное приложение пока одно, версионирование сразу закладываю на уровне префикса /api/v1, потому что вторая версия приложения появляется быстрее, чем кажется на старте проекта.

Дальше - ресурсные контроллеры через apiResource, никакой ручной раздачи роутов на каждый CRUD-метод:

Route::prefix('v1')->middleware('auth:sanctum')->group(function () {
    Route::apiResource('orders', OrderController::class);
    Route::get('/user', function (Request $request) {
        return $request->user();
    });
});

Для мобильного клиента важно, чтобы каждый эндпоинт возвращал предсказуемый JSON независимо от того, вызван он из приложения или из Postman на этапе тестирования. Для этого использую API Resources - отдельный слой между моделью Eloquent и ответом API:

class OrderResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'status' => $this->status,
            'total' => $this->total,
            'items' => OrderItemResource::collection($this->items),
            'created_at' => $this->created_at->toIso8601String(),
        ];
    }
}

Разделяю Resource и модель осознанно - так поле created_at я привожу к ISO 8601 один раз в одном месте, а не разбираюсь потом, почему в iOS-приложении дата парсится нормально, а в Android падает с ошибкой формата.

Sanctum или Passport - что выбираю для аутентификации в мобильном приложении

Для большинства мобильных бэкендов беру Sanctum - он выдаёт персональный токен на устройство, не требует OAuth2-хендшейка и настраивается за пару часов. Passport оставляю для кейсов, когда сторонние сервисы должны получать доступ к API от имени пользователя по OAuth2 - например, когда партнёрская интеграция заходит через ваш API.

Критерий Sanctum Passport
Тип токенов Personal Access Token OAuth2 (Bearer, refresh)
Сложность настройки Низкая, 1-2 часа Выше, нужен OAuth-клиент и миграции
Подходит для Своё мобильное или SPA-приложение Сторонние интеграции, партнёрские API
Отзыв токена Удаление записи в БД Через refresh-токены и scopes

На мобильном клиенте логика простая: логин отдаёт токен, токен кладётся в Keychain или Keystore, дальше идёт в заголовке Authorization: Bearer. Ротацию токенов делаю через отдельный эндпоинт /refresh, а не через долгоживущий токен без срока - иначе при утере телефона придётся вручную чистить токены в базе сразу для всех пользователей.

Бесплатный материал

🎁 Полезный скрипт в подарок

Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.

Без спама. Отписка в 1 клик.

Валидация запросов и единый формат ошибок

Мобильное приложение не должно парсить HTML-страницу с ошибкой 500 - оно ждёт JSON строго определённой структуры. Поэтому первым делом переопределяю рендер исключений в app/Exceptions/Handler.php (или в bootstrap/app.php начиная с Laravel 11), чтобы любая ошибка возвращалась в едином формате: код, сообщение, детали по полям.

Валидацию выношу в Form Request классы - контроллер остаётся тонким, а правила переиспользуются между эндпоинтами создания и обновления записи.

public function render($request, Throwable $exception)
{
    if ($request->expectsJson()) {
        return response()->json([
            'message' => $exception->getMessage(),
            'errors' => method_exists($exception, 'errors') ? $exception->errors() : null,
        ], $this->isHttpException($exception) ? $exception->getStatusCode() : 500);
    }

    return parent::render($request, $exception);
}

Продакшен: кэш, очереди и лимиты запросов

Как только API уходит в продакшен, три вещи спасают от падений под нагрузкой из мобильного приложения: Redis-кэш для справочников и каталога, очереди для всего, что не обязано отвечать мгновенно (push-уведомления, отправка чека, синхронизация статуса заказа с СДЭК), и throttle-мидлвар на каждый роут.

Лимит запросов настраиваю не глобально, а по группам - авторизационные эндпоинты 5-10 запросов в минуту с одного IP, чтение каталога - 60-100, потому что мобильное приложение может дёргать список товаров при каждом открытии экрана.

Отдельно слежу за N+1 запросами - на мобильном API это ощущается сильнее, чем на вебе, потому что один экран приложения часто дёргает 3-4 связанные сущности разом. Eager loading через with() в контроллере убирает большую часть таких проблем ещё на этапе разработки.

Если после релиза нужно перекладывать события заказа в CRM или отправлять уведомление в чат без написания отдельного сервиса, обычно подключаю автоматизацию в n8n - вебхук из Laravel улетает в сценарий, а дальше n8n сам раскладывает данные по нужным системам.

Тестирование и документация перед релизом

Feature-тесты в Laravel пишу для каждого эндпоинта, который трогает деньги, авторизацию или пользовательские данные - остальное покрываю по необходимости. PHPUnit с RefreshDatabase гоняет тесты за секунды, и это тот минимум, без которого я не отдаю API мобильной команде на интеграцию.

Документацию собираю через Scribe - он парсит Form Request и Resource классы и генерирует читаемую OpenAPI-спецификацию без ручного дублирования описаний. Мобильным разработчикам отдаю готовую Postman-коллекцию, чтобы не тратить день на созвоны с объяснением, что означает каждое поле в ответе.

API и серверная часть под SPA

API / Бэкенд

от 100 000 ₽

Подробнее →

Частые вопросы

Сколько времени занимает разработка REST API на Laravel для мобильного приложения?

Простой MVP на 10-15 эндпоинтов без сложной бизнес-логики закрываю за 2-3 недели. Бэкенд с оплатой, push-уведомлениями и синхронизацией доставки занимает 4-6 недель. Разработка бэкенда на Laravel у меня начинается от 100 000 ₽ - точная сумма зависит от количества сущностей и интеграций.

Чем Sanctum лучше Passport для мобильного приложения?

Sanctum проще и быстрее в настройке, потому что не требует полного OAuth2-цикла - выдаёт токен на устройство и всё. Passport оправдан, только если сторонние сервисы должны получать доступ к вашему API от имени пользователя по OAuth2, а для большинства мобильных приложений это не требуется.

Нужна ли отдельная документация API для мобильной команды?

Да, и лучше генерировать её из кода, а не писать вручную в вики, которая устареет через неделю. Scribe или L5-Swagger снимают необходимость дублировать описание полей в двух местах - спецификация обновляется вместе с кодом.

Как тестировать REST API на Laravel перед релизом мобильного приложения?

Пишу Feature-тесты на PHPUnit для критичных сценариев - регистрация, оплата, изменение статуса заказа, и прогоняю их в CI перед каждым деплоем. Дополнительно собираю Postman-коллекцию с реальными запросами, чтобы мобильная команда могла тестировать эндпоинты руками ещё до того, как разработка интерфейса дойдёт до конкретного экрана.

Есть задача?

Обсудим в мессенджере

Расскажите, что нужно сделать — отвечу в течение 4 часов в рабочее время. Первая консультация бесплатно.

Самозанятый Калинкин Н. А. · работаю с физлицами и юрлицами

Продолжая пользование настоящим сайтом Вы выражаете своё согласие на обработку Ваших персональных данных (файлов куки) с использованием Yandex.Metrika.
Понятно