Как спроектировать API для мобильного приложения, чтобы бэкенд не стал бутылочным горлышком
Перед первой строкой кода зафиксируйте четыре вещи: контракт API, авторизацию на уровне объекта (а не только токена), схему версионирования и стратегию кэша. Прямой доступ мобильного клиента к базе — быстрый способ получить MVP и почти гарантированно сломать его на втором релизе.

Заказ «добавьте нам мобильное приложение» чаще всего приходит в веб-команду, у которой уже есть сайт, бэкенд и опыт с REST или GraphQL — но нет опыта именно с мобильными клиентами. Разница небольшая на вид и существенная на практике: мобильное приложение живёт на устройстве пользователя неделями и месяцами, не обновляется мгновенно и не может просто «перезагрузить страницу», если контракт с сервером поменялся.
Backend и API-слой для такого приложения логично остаются в зоне веб-команды — это те же навыки, что и для сайта. А вот за сам нативный клиент и его публикацию в App Store и Google Play обычно отвечает уже отдельная команда — например, команда YUSMP Group, которая специализируется на мобильной разработке и доведёт готовый API до реального приложения в сторах.
Зачем мобильному приложению отдельный API-слой, а не прямой доступ к базе
API-слой — это промежуточный сервис, который принимает запросы от мобильного клиента, превращает их в операции над базой и бизнес-логикой и возвращает ответ в предсказуемом формате, не раскрывая клиенту внутреннее устройство хранилища. Для команды, у которой уже есть сайт с собственной логикой, соблазн дать мобильному приложению прямой доступ к той же базе или к внутренним методам монолита понятен — это быстрее на старте.
У прямого доступа есть три системные проблемы. Во-первых, любое изменение схемы базы данных автоматически ломает клиент, потому что между ними нет буфера. Во-вторых, бизнес-правила начинают дублироваться: часть логики живёт в вебе, часть пишется заново под мобильное приложение, и со временем они расходятся. В-третьих, у мобильного клиента появляется слишком много прав — он видит структуру данных, которую не должен видеть, и может отправить запрос, который никто не предусматривал.
API-слой закрывает все три проблемы одним приёмом: он фиксирует контракт между клиентом и сервером, стабильный независимо от того, как меняется реализация за ним. Мобильное приложение продолжает работать со старой версией контракта, даже когда бэкенд полностью переписывает внутреннюю логику.
Как выбрать архитектуру для старта: монолит, микросервисы или BaaS
Для первого мобильного приложения почти всегда правильный ответ — не трогать архитектуру вообще. Если у компании уже есть монолитный веб-бэкенд, API-слой для мобильного клиента логичнее добавить поверх него отдельным модулем, а не затевать миграцию на микросервисы ради одного нового клиента.
Полноценное разделение на микросервисы имеет смысл, когда команда уже столкнулась с реальными проблемами масштабирования монолита — независимо от мобильного приложения. Делать это заранее, «на будущее», обычно означает заплатить архитектурной сложностью за проблему, которой ещё нет.
Третий вариант — BaaS (Backend-as-a-Service вроде Firebase или Supabase) — подходит, если приложение запускается с нуля, без существующего веб-бэкенда, и команда хочет минимизировать серверную часть на старте. Для компании с уже работающим веб-бэкендом и командой, которая его поддерживает, BaaS обычно избыточен: он решает проблему, которой у вас нет, и добавляет зависимость от стороннего вендора.
REST или GraphQL — что проще поддерживать на старте
Выбор протокола решается раньше архитектуры, потому что он определяет форму контракта. Для одного мобильного клиента с умеренным числом экранов обычно хватает REST — он проще в отладке, лучше кэшируется на уровне HTTP и не требует отдельного слоя резолверов.
| Критерий | REST | GraphQL |
|---|---|---|
| Порог входа | Ниже, стандартные инструменты и соглашения | Выше, нужен отдельный слой схемы и резолверов |
| Кэширование | Стандартное HTTP-кэширование из коробки | Нужен отдельный слой кэша на клиенте |
| Когда оправдан | Один-два клиента, простые однотипные экраны | Несколько разных клиентов с разными требованиями к данным |
GraphQL оправдан, когда у приложения несколько разных клиентов — например, мобильное приложение и отдельная админ-панель, — которым нужны разные наборы полей с одного и того же набора сущностей, и важно не плодить под каждый случай отдельный REST-эндпоинт.
Контракт раньше кода: что фиксировать до первой строки реализации
Самая дорогая ошибка в проектировании API для мобильного приложения — начать с реализации, а не с контракта. Контракт описывает, что именно умеет каждый эндпоинт: обязательные и опциональные поля запроса, точный формат ответа, список возможных кодов ошибок и типы данных каждого поля.
Зафиксировать это стоит до того, как написана первая строка backend-кода, по простой причине: изменить контракт на бумаге — вопрос одного обсуждения с мобильной командой, а изменить его после того, как обе стороны уже написали код под него, — это рассинхрон релизов и доработки сразу с обеих сторон.
Отдельно стоит зафиксировать единый формат ошибок для всего API — один и тот же набор полей (код ошибки, человекочитаемое сообщение, опционально список невалидных полей) для любого эндпоинта. Если каждый метод возвращает ошибки по-своему, мобильному клиенту приходится писать отдельную обработку под каждый случай — и именно тут чаще всего ломается приложение в проде, не потому что бэкенд упал, а потому что ответ с ошибкой пришёл в неожиданном формате.
Авторизация: почему проверка токена — это не то же самое, что проверка прав на объект
Проверка валидности токена отвечает на вопрос «кто этот пользователь», но не отвечает на вопрос «имеет ли право именно этот пользователь получить именно этот конкретный объект». Это разные проверки, и пропустить вторую — одна из самых частых ошибок в API для мобильных приложений.
Типичный пример: эндпоинт вида «получить заказ по идентификатору» корректно проверяет, что токен валиден, но не проверяет, что заказ с этим id принадлежит именно авторизованному пользователю. Любой пользователь, подобрав числовой идентификатор, может получить чужой заказ. Такая уязвимость называется нарушением авторизации на уровне объекта и регулярно попадает в верхние строчки отраслевых рейтингов проблем API.
Правило простое: каждый эндпоинт, который принимает идентификатор объекта, обязан явно проверять, что этот объект принадлежит текущему авторизованному пользователю — а не полагаться на то, что клиент «и так не должен» запрашивать чужие данные. Подробный разбор контрактного подхода к API поверх существующей системы есть в материале на Habr.
Версионирование API без бесконечных копий методов
Мобильные приложения обновляются медленнее, чем бэкенд: часть пользователей месяцами сидит на старой версии приложения, которая ждёт API в старом формате. Поэтому версионирование — не опциональная практика «на будущее», а требование с первого релиза.
Самый простой рабочий подход для старта — версия в URL с явным сроком жизни старой версии, например полгода после выхода новой. Это не требует поддерживать бесконечное количество копий одного метода: вместо этого фиксируется дата, после которой старая версия отключается, и эта дата заранее сообщается мобильной команде.
Смежная практика — кэширование. Эндпоинты, которые отдают редко меняющиеся данные (справочники, настройки), стоит кэшировать на уровне HTTP-заголовков — это снижает нагрузку на бэкенд и ускоряет приложение без единой строчки логики на клиенте. Версионирование и кэш вместе закрывают ту часть API, которая иначе вскрывается только после первого крупного релиза, когда откатывать уже поздно.
Частые вопросы
Нужен ли отдельный бэкенд, если у компании уже есть сайт с API?
Отдельный бэкенд необязателен. В большинстве случаев достаточно добавить к существующему бэкенду отдельный API-слой для мобильного клиента — со своим контрактом и версионированием, но на той же инфраструктуре.
Что делать со старыми версиями приложения после смены API?
Держать старую версию API живой до заранее объявленной даты отключения (обычно несколько месяцев), а не выключать её сразу после релиза новой — иначе приложение у части пользователей просто перестанет работать.
REST или GraphQL — что выбрать для нового мобильного приложения?
Для одного мобильного клиента с умеренным числом экранов обычно проще и быстрее REST. GraphQL оправдан, когда с одними и теми же данными работает несколько разных клиентов с разными требованиями к полям.
Как понять, что пора переходить от монолита к отдельному API-слою?
Как только появляется второй клиент — мобильное приложение — помимо сайта, пора заводить отдельный API-слой. Сам переход к микросервисам из монолита — отдельное решение, не обязательно связанное с мобильным приложением.
Что проверить в безопасности API перед релизом мобильного приложения?
Как минимум — что каждый эндпоинт с идентификатором объекта проверяет права именно на этот объект, а не только валидность токена, и что единый формат ошибок не раскрывает внутренние детали реализации.
Сколько времени занимает проектирование API-слоя для MVP?
Зависит от числа экранов и сущностей в приложении, но сам контракт для MVP обычно можно зафиксировать за несколько дней обсуждений с мобильной командой — до того, как начнётся реализация.



