Услуги Портфолио Контакты БлогНовости +7 (800) 511‑32‑27 Обсудить проект
Статьи

Клиент-серверная архитектура: как разрабатывать web API

20 октября 2022·13 мин чтения
Логотип YuSMP Group
Автор материалаРедакция компании YuSMP GroupБлог YuSMP Group
Профиль редакции
Клиент-серверная архитектура: как разрабатывать web API

Коротко. Web API — интерфейс, через который клиентское и серверное приложения обмениваются данными по HTTP. Чаще всего это REST на JSON, но для сложных клиентов и высоконагруженных сервисов выбирают GraphQL или gRPC. Хороший API проектируют по шести принципам REST, версионируют и защищают аутентификацией с первого релиза, а документируют через OpenAPI — тогда его легко расширять и подключать новым командам. Ниже разберём архитектуру, критерии выбора подхода, типичные ошибки и дадим таблицу HTTP-кодов.

Не существует единого подхода к разработке API или даже к тому, как «правильно» работать с API. Вместо этого нам нужно опираться на отраслевые рекомендации по проектированию, лучшие практики и шаблоны — рынок API растёт вместе со спросом на интеграции, и большинство современных продуктов, от мобильных приложений до внутренних CRM, обмениваются данными именно через web API, а не через прямой доступ к базе.

Мы в YuSMP Group проектируем и разрабатываем API в рамках услуги backend-разработки — от простого REST-сервиса для мобильного приложения до высоконагруженной интеграционной платформы. В блоге студии web-разработки YuSMP Group разберём понятие API, шесть принципов REST, чем он отличается от GraphQL и gRPC, как версионировать и защищать API, а также какие ошибки чаще всего допускают на старте.

Что такое API, виды и назначение

API-интерфейсы стали наиболее распространенным способом взаимодействия программ и устройств друг с другом в современных вычислениях. 

Web API — это набор правил, описывающих, как одна программа может подключиться и взаимодействовать с другой. Для чего и как использовать API: эти конструкции нужны для облегчения процесса программирования. Application Programming Interfaces уже содержат сложную часть кода, которую нужно только внедрить.

Как следует из названия, REST API передает при каждом запросе состояние любой транзакции, что дает преимущество в дизайне, производительности и ресурсах по сравнению с другими подходами. REST разрабатывался более двух десятилетий и является очень распространенным подходом для клиент-серверных архитектур.

REST API

REST API — это подход, фундаментальной концепцией которого является ресурс. Ресурс — это объект с типом, связанными данными, отношениями с другими ресурсами и набором методов, которые с ним работают. Это очень похоже на идею объектов в программировании, хотя определено только несколько стандартных методов, типичных для HTTP GET, POST, PUT и DELETE. Ресурсы могут существовать сами по себе или быть сгруппированы в коллекции, которые сами являются ресурсами.

В современных вычислениях общая модель — также фундаментальная для REST API — является клиент серверное взаимодействие. Когда клиент, которому нужен ресурс, идентифицирует и связывается с серверной частью сайта. Практически весь облачный трафик управляется таким образом, поскольку он обеспечивает максимальную гибкость. Этот принцип также хорошо работает для так называемых «бессерверных» архитектур приложений, где сервис-брокер занимает место сервера, известного клиенту.

REST, GraphQL и gRPC: как выбрать подход

REST — не единственный способ построить web API, и для части задач он не самый удачный. У современного бэкенда обычно есть выбор между тремя архитектурными стилями, и выбор влияет на скорость разработки клиента, объём трафика и сложность поддержки.

ПодходФормат данныхСильные стороныКогда выбирать
RESTJSON поверх HTTPПростой, кэшируется, понятен любому клиенту, огромная экосистема инструментовПубличные API, мобильные и веб-клиенты, большинство CRUD-сервисов
GraphQLJSON, единая точка входаКлиент сам описывает, какие поля нужны — нет лишних полей и лишних запросовСложные экраны с данными из нескольких источников, мобильные клиенты с ограниченным трафиком
gRPCProtocol Buffers (бинарный)Высокая скорость и малый вес сообщений, строгая типизация, потоковая передачаВнутреннее взаимодействие между микросервисами, высоконагруженные системы

На практике эти подходы не исключают друг друга: внешний REST API для мобильного приложения может внутри дёргать микросервисы по gRPC — клиент об этом даже не узнает. Архитектуру выбираем под конкретную задачу в рамках разработки API, а не следуем моде на конкретную технологию.

Сравнение трёх архитектурных стилей API: REST, GraphQL и gRPC

Шесть правил проектирования REST API

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

1. Единый интерфейс

Все запросы, сделанные через REST API, должны соответствовать правилам форматирования этого API. Независимо от того, какой клиент делает запрос, он должен поместить каждую часть информации туда, где ее поместил бы любой другой клиент. Одним из примеров является URL-адрес или унифицированный указатель ресурса, используемый для идентификации ресурсов через HTTP, который является одним из примеров универсального идентификатора ресурса (URI), который может иметь более широкие области действия.

2. Разделение клиент-сервер

API REST требуют, чтобы клиент, серверное приложения были полностью независимы друг от друга. Клиенту нужно знать только полное имя ресурса, который ему нужен в виртуальном пространстве, разрешенном API. В противном случае единственными знаниями клиента и сервера друг о друге являются данные, которыми обмениваются транзакции API.

3. Безгражданство

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

4. Кэшируемость

В отличие от безгражданства сервера для каждого клиента, ресурсы должны кэшироваться в одной или нескольких точках внутри или между клиентом и сервером. В случае с сервером, если конкретный ресурс был обслужен и он, вероятно, будет снова запрошен в течение определенного времени, его следует кэшировать для более быстрого последующего ответа. Клиент должен принять аналогичное решение о полученных ресурсах. Сервер должен указать через API, можно ли безопасно кэшировать ресурс локально на клиенте, включая время жизни данных, где это уместно. Дизайн кэша, хотя и не является частью спецификации RESTful API, имеет решающее значение для производительности, и разработчики API должны знать, как это может применяться на практике.

5. Многоуровневая системная архитектура

Следствием разделения клиент-сервер, отсутствия состояния и возможности кэширования является то, что клиент не может делать предположений о том, взаимодействует ли он напрямую с сервером, содержащим определенный ресурс, или обслуживается ли он промежуточным звеном, таким как сервисный брокер, балансировщик нагрузки, система доставки контента или другая подсистема, расположенная ближе к клиенту, чем к серверу. Это дает разработчикам систем и инфраструктуры значительную гибкость, позволяющую максимально повысить эффективность и надежность удовлетворения запросов в глобальной проводной и беспроводной инфраструктуре. Он лежит в основе функциональности граничных вычислений.

6. Код по запросу

Хотя API-интерфейсы REST могут и часто предоставляют только данные для потребления клиентом, все чаще код доставляется для запуска на клиент-сервере Java, клиент-сервере Android или веб-приложении Javascript. Если это реализовано, то такой код может быть запущен только по требованию клиента.

Услуги мобильной разработки
Узнайте цену

Структура URL и коды ответов HTTP

Единый интерфейс из правил REST (см. выше) на практике означает предсказуемую структуру адресов и предсказуемые коды ответов. Разработчику клиента не нужно лезть в документацию за каждым запросом — поведение угадывается по аналогии.

Именование ресурсов

Ресурсы в URL называют существительными во множественном числе, а не глаголами: /orders, а не /getOrders. Действие определяет HTTP-метод (GET, POST, PUT, PATCH, DELETE), а не слово в адресе. Вложенность отражает отношения между объектами: /orders/42/items — список позиций конкретного заказа.

Коды ответов

Каждый ответ сервера сопровождается HTTP-статусом, который однозначно говорит клиенту, что произошло — без разбора тела ответа.

КодКлассЧто означает
200 OKУспехЗапрос выполнен, тело ответа содержит данные
201 CreatedУспехРесурс создан, обычно в ответ на POST
204 No ContentУспехЗапрос выполнен, возвращать нечего (например, после DELETE)
400 Bad RequestОшибка клиентаНекорректные данные в запросе
401 UnauthorizedОшибка клиентаНет или недействительны данные аутентификации
403 ForbiddenОшибка клиентаКлиент аутентифицирован, но у него нет прав на действие
404 Not FoundОшибка клиентаРесурс с таким идентификатором не существует
429 Too Many RequestsОшибка клиентаПревышен лимит запросов (rate limit)
500 Internal Server ErrorОшибка сервераНеобработанное исключение на стороне сервера

Отдельная частая ошибка — возвращать 200 OK с телом вида {"error": "не найдено"}. Формально запрос «успешен», хотя по сути произошла ошибка, и клиенту приходится разбирать тело ответа вместо того, чтобы читать статус-код.

Как работают API REST

API-интерфейсы REST могут обрабатывать практически любой запрос на доступ, формат данных, управление ресурсами или сообщения о состоянии, но правило отсутствия состояния означает, что каждый запрос должен содержать любую аутентификацию, необходимую для проверки запроса, точное определение требуемого ресурса и точное требуемое действие.

Например, не-RESTful API файловой системы может ответить на запрос на чтение файла, вернув дескриптор файла, небольшой токен, назначенный сеансу, чтобы клиент мог выполнять повторные чтения, просто ссылаясь на этот дескриптор. Вместо этого, API REST должен был бы каждый раз отправлять авторизацию клиента, а также полный точный идентификатор ресурса вместе с точным расположением в файле данных для чтения. Клиент должен следить.

API-интерфейсы REST передают всю эту информацию через комбинацию заголовков и полей параметров и могут обмениваться фактическими данными в любом формате. Очень распространенным стандартом является JSON, формат нотации объектов Javascript, который, несмотря на свое название, читается как людьми, так и машинами, на глаз или с использованием любого из популярных языков программирования.

При проектировании REST API необходимо учитывать эффективность, особенно там, где необходимо обрабатывать большие объемы данных или потоки, критичные ко времени, или, наоборот, небольшие объемы данных из источников с ограниченными ресурсами, таких как системы IoT.

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

Как только у API появляется хотя бы один внешний клиент, менять формат ответа «на лету» нельзя — это сломает всех, кто уже интегрировался. Версионирование решает эту проблему: старые клиенты продолжают работать со старой версией, пока не переключатся на новую.

Три распространённых способа задать версию:

  • В URL — /v1/orders, /v2/orders. Самый явный и удобный для отладки способ, но версия «протекает» в адреса, которые видит клиент.
  • В заголовке запроса — например Accept: application/vnd.company.v2+json. Адрес остаётся неизменным, но версию сложнее увидеть в логах и труднее протестировать вручную.
  • Через query-параметр — /orders?version=2. Просто внедрить, но легко забыть указать параметр и получить версию по умолчанию.

Правило, которое экономит больше всего времени: закладывать версионирование в API с первого релиза, даже если пока есть только v1. Добавить его задним числом, когда уже есть работающие интеграции, обычно дороже.

Аутентификация и безопасность API

Открытый наружу API — это дополнительная точка входа в систему, и её нужно защищать так же внимательно, как форму входа на сайте.

Способы аутентификации

  • API-ключ — простая строка, которую клиент передаёт в заголовке. Подходит для внутренних интеграций и партнёрских сервисов, но плохо подходит для конечных пользователей: ключ сложно отозвать точечно.
  • OAuth 2.0 — клиент получает временный токен доступа после авторизации пользователя. Стандарт для API, к которым подключаются сторонние приложения (вход через соцсеть, интеграции с маркетплейсами).
  • JWT (JSON Web Token) — подписанный токен, который сервер может проверить без обращения к базе данных на каждый запрос. Удобен для масштабирования, но требует аккуратной работы со временем жизни токена и его отзывом.

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

Аутентификация и защита API: ключ доступа между клиентом и сервером

Пагинация, фильтрация и сортировка

Коллекция ресурсов редко умещается в один ответ. Когда заказов в базе миллион, отдавать их все одним запросом — гарантированный способ положить сервер и клиента.

Пагинация

Два основных подхода: постраничная (?page=2&limit=20) — проста в реализации и понятна пользователю, но «плывёт» при добавлении новых записей между запросами; и курсорная (?cursor=eyJpZCI6NDJ9) — устойчива к изменениям данных и быстрее работает на больших объёмах, но курсор нельзя произвольно промотать на конкретную страницу.

Фильтрация и сортировка

Фильтры задают через query-параметры: /orders?status=paid&created_after=2026-01-01. Сортировку — отдельным параметром с указанием поля и направления: /orders?sort=-created_at для сортировки по убыванию даты создания. Для сложных случаев (несколько условий, полнотекстовый поиск) в API можно добавить отдельный эндпоинт поиска вместо того, чтобы перегружать GET-параметрами один маршрут.

Документирование API: OpenAPI и Swagger

API без документации требует от каждого нового клиента читать исходный код бэкенда или переписываться с разработчиками в мессенджере. Это не масштабируется даже внутри одной компании.

OpenAPI Specification (бывший Swagger) — отраслевой стандарт описания REST API в формате YAML или JSON: какие есть эндпоинты, какие параметры принимают, что возвращают и какие коды ошибок возможны. По этому описанию инструменты вроде Swagger UI автоматически строят интерактивную документацию, где можно отправить тестовый запрос прямо из браузера, а генераторы кода — собрать клиентские SDK на нужном языке.

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

Интерактивная документация API по спецификации OpenAPI

Типичные ошибки при проектировании API

ОшибкаПоследствиеКак избежать
Глаголы в URL (/getUserOrders)Непредсказуемая структура, сложно масштабировать на новые ресурсыСуществительные во множественном числе + HTTP-методы
Отсутствие версионированияЛюбое изменение формата ответа ломает всех текущих клиентовВерсия в URL или заголовке с первого релиза
200 OK на ошибкуКлиент обязан разбирать тело каждого ответа, чтобы понять, что произошлоИспользовать полный диапазон HTTP-кодов
Отдача всей коллекции без пагинацииРост базы данных превращается в деградацию и таймауты APIПагинация и лимиты изначально, даже при небольшом объёме данных
Нет rate limitingОдин агрессивный клиент или бот кладёт сервис для всех остальныхОграничение частоты запросов на уровне API-шлюза
Документация вручную в Word или ConfluenceРасходится с реальным кодом уже через пару спринтовOpenAPI-спецификация, сгенерированная или проверяемая тестами

Тестирование и мониторинг API

Работающий в проде API нельзя протестировать один раз и забыть — над ним постоянно меняется код, добавляются эндпоинты, обновляются зависимости.

Виды тестов

  • Юнит-тесты — проверяют отдельные функции бизнес-логики в изоляции, без реального HTTP-запроса.
  • Интеграционные тесты — поднимают API целиком (обычно с тестовой базой данных) и проверяют реальные запросы и ответы.
  • Контрактные тесты — сверяют фактическое поведение API с OpenAPI-спецификацией, чтобы документация не расходилась с кодом.
  • Нагрузочные тесты — показывают, сколько запросов в секунду выдерживает API и где он начинает деградировать, до того как это увидят реальные пользователи.

Для ручной проверки удобны Postman, Insomnia или обычный curl — можно быстро собрать запрос и посмотреть ответ, не открывая клиентское приложение.

Мониторинг в проде

После запуска важно отслеживать долю ответов с кодами 5xx, время ответа по эндпоинтам (особенно перцентили p95 и p99 — медиана скрывает медленные запросы) и всплески 429 — сигнал, что клиенты чаще ожидаемого упираются в лимиты. Без этого проблемы API становятся заметны не по метрикам, а по жалобам пользователей.

Чек-лист перед запуском API

  1. Ресурсы названы существительными во множественном числе, действие задаёт HTTP-метод.
  2. Версия зафиксирована в URL или заголовке с первого релиза.
  3. Используется полный диапазон HTTP-кодов, а не только 200 и 500.
  4. Коллекции отдаются с пагинацией и лимитом по умолчанию.
  5. Настроена аутентификация, подходящая сценарию: API-ключ, OAuth 2.0 или JWT.
  6. Включён HTTPS без исключений и rate limiting на уровне шлюза.
  7. Есть OpenAPI-спецификация, синхронизированная с реальным кодом.
  8. Настроен мониторинг ошибок 5xx и времени ответа по эндпоинтам.

Резюме

Создавать API сложно. Помимо длительных встреч с заинтересованными сторонами, выбора правильного стека технологий и построения соответствующей модели распределения данных, существует множество более мелких деталей, которые можно упустить из виду. Лучше доверить это профессионалам веб-разработки и мобильной разработки, которые занимаются созданием сайтов под ключ, приложениями и владеют передовыми технологиями.

Частые вопросы о разработке web API (FAQ)

Чем Web API отличается от REST API?

Web API — общее понятие: любой интерфейс, через который приложения обмениваются данными по HTTP. REST API — один из архитектурных стилей построения Web API, наиболее распространённый, но не единственный: есть ещё GraphQL, gRPC и SOAP.

Нужен ли GraphQL, если уже есть REST?

Не обязательно. GraphQL решает проблему over-fetching (клиент получает лишние поля) и under-fetching (нужно несколько запросов), но добавляет сложность на сервере — кэширование и лимиты запросов приходится реализовывать вручную. Для большинства CRUD-сервисов REST остаётся более простым и дешёвым решением.

Сколько стоит разработка web API?

Зависит от количества эндпоинтов, сложности бизнес-логики и требований к безопасности. Простой REST API с базовой аутентификацией для одного мобильного приложения обычно дешевле и быстрее в разработке, чем интеграционная платформа с десятками внешних партнёров. Точную оценку даёт техническое задание — можно обсудить в рамках разработки API в YuSMP Group.

Как выбрать формат аутентификации для API?

Для внутренних интеграций между своими сервисами достаточно API-ключа. Если к API подключаются сторонние приложения от имени пользователя — нужен OAuth 2.0. Для высоконагруженных публичных API с собственными пользователями чаще выбирают JWT — он не требует обращения к базе на каждый запрос.

Обязательно ли версионировать API с самого начала?

Да, даже если версия пока одна. Добавить версионирование в работающий API с активными интеграциями сложнее и рискованнее, чем заложить его архитектурно на старте.

Что такое rate limiting и зачем он нужен?

Ограничение количества запросов от одного клиента за промежуток времени. Защищает сервер от перегрузки — случайной (баг в клиенте, который долбит API в цикле) или намеренной (парсинг, DDoS-атака). Обычно реализуется на уровне API-шлюза и возвращает код 429 при превышении лимита.

Можно ли обойтись без документации API, если команда маленькая?

Формально можно, но это временная экономия. Как только к API подключается второй разработчик, новый фронтенд-клиент или партнёр, отсутствие документации превращается в постоянные вопросы в чате и рассинхрон между фактическим и ожидаемым поведением сервиса. OpenAPI-спецификацию дешевле завести сразу.

Обсудим ваш проект?

Соберём команду под вашу задачу и оценим проект за 2 дня — бесплатно.

Обсудить проект