Контракт описывает и успех, и сбой
- 01ЗапросСмысл и данные
- 02ГраницаПрава и ограничения
- 03ОтветРезультат или ошибка
- 04ПовторСовместимость и эффект
За годы ревью интеграций я не раз встречал один набор решений: POST для чтения и удаления, 200 OK для любой ошибки, описание полей в отдельной таблице и отсутствие правил совместимости.
Пример ниже композитный, но узнаваемый:
POST /api/client/get
POST /api/client/delete
POST /api/client/getStatus
Сам по себе POST не запрещён. Проблема возникает, когда контракт не объясняет семантику, возможность повтора, ошибки и жизненный цикл данных. Именно этому я уделял больше всего внимания на курсе по системному анализу.
API — это не синоним REST
| Подход | Модель взаимодействия | Контракт | Где полезен | Основная цена |
|---|---|---|---|---|
| HTTP resource API | Ресурсы и семантика HTTP | OpenAPI — распространённый выбор | Публичные и внутренние API, веб-интеграции | Дисциплина совместимости и единых соглашений |
| SOAP | XML-сообщения и операции | WSDL + XSD | Существующие enterprise- и WS-*-экосистемы | Сложность спецификаций и инструментов |
| GraphQL | Запрос к типизированному графу | GraphQL schema | Несколько клиентских представлений одних данных | Стоимость резолверов, запросов и governance |
| JSON-RPC | Вызов метода с параметрами | Договорённость или внешняя схема | Компактные RPC-интерфейсы и внутренние утилиты | Мало встроенных правил эволюции и обнаружения |
| gRPC | Типизированные RPC-вызовы | .proto | Внутренние сервисы, streaming, генерация клиентов | Бинарный протокол и зависимость от toolchain |
REST — архитектурный стиль, а не формат данных. Многие production API корректнее называть HTTP API с JSON: они используют URI, методы и коды HTTP, но не реализуют весь набор ограничений REST. Это не дефект, если контракт честно описан.
Семантика HTTP без мифов
HTTP stateless в том смысле, что каждый запрос должен быть понятен сам по себе. Сервер при этом может хранить данные, сессии и состояние ресурсов; нельзя лишь полагаться на неявный контекст конкретного соединения.
Методы выражают намерение:
GETчитает представление и имеет безопасную, идемпотентную семантику;POSTпередаёт ресурсу данные для обработки — создание является частым, но не единственным сценарием;PUTсоздаёт или заменяет состояние целевого ресурса и идемпотентен по предусмотренному эффекту;PATCHприменяет частичное изменение и не обязан быть идемпотентным;DELETEудаляет связь с ресурсом и идемпотентен по предусмотренному эффекту.
Если процедура плохо ложится на ресурсную модель, не нужно маскировать её любой ценой. Например, POST /risk-assessments может означать создание результата оценки. Для явного RPC-вызова честнее рассмотреть JSON-RPC или gRPC, чем придумывать искусственный ресурс.
Коды ответа тоже являются частью контракта:
200 OK— запрос успешно обработан;201 Created— создан новый ресурс, обычно сLocation;204 No Content— успех без тела;400 Bad Request— запрос некорректен для обработки;401 Unauthorized— не предоставлены корректные данные аутентификации;403 Forbidden— сервер понял запрос, но отказывает в доступе;404 Not Found— целевой ресурс не найден или не раскрывается;409 Conflict— запрос конфликтует с текущим состоянием;500 Internal Server Error— сервер столкнулся с неожиданным условием.
Возвращать 200 при сбое обработки, который контракт описывает как HTTP-ошибку, — плохая практика: gateway, метрики и клиенты теряют стандартный сигнал. Но отрицательный бизнес-результат не обязательно ошибка запроса. Например, успешно выполненная оценка с результатом «не одобрено» может вернуть 200: решение находится в теле ответа, а код сообщает об успешной обработке. Это различие нужно описать в контракте. У GraphQL другая модель частичного результата, где ответ может содержать и data, и errors; её нельзя механически переносить на любой JSON API.
SOAP: messaging framework, а не готовая транзакция
SOAP задаёт XML-envelope и модель обработки сообщений. WSDL и XSD дают зрелое описание операций и типов, поэтому технология остаётся полезной в системах, где такой контракт уже является стандартом взаимодействия.
WS-Security, WS-ReliableMessaging и транзакционные расширения — отдельные спецификации и профили. Наличие SOAP не включает шифрование, гарантированную доставку или распределённую транзакцию автоматически. Эти свойства зависят от выбранных расширений, binding, реализации и общей архитектуры.
Выбирать SOAP стоит ради совместимости с существующим ландшафтом и конкретных требований к стеку WS-*, а не по формуле «нужна надёжность — берём SOAP».
GraphQL: гибкость запроса требует governance
GraphQL публикует типизированную схему, а клиент выбирает нужные поля. Это удобно, когда веб, мобильное приложение и внутренний интерфейс используют разные представления одних сущностей.
Сложность переезжает на сервер:
- резолверы могут породить N+1-запросы;
- глубину и стоимость запросов нужно ограничивать;
- авторизация должна работать на уровне бизнес-объектов и полей;
- изменение схемы требует deprecation-политики;
- производительность нельзя оценить только числом HTTP-вызовов.
GraphQL чаще передают по HTTP в JSON, но спецификация языка не привязана к одному транспорту. Query может идти через GET, что позволяет использовать HTTP-кеширование; также применяются persisted documents. Поэтому «GraphQL невозможно кешировать» — слишком сильное утверждение.
gRPC: контракт и streaming, а не магическая latency
gRPC описывает сервисы и сообщения в .proto, генерирует клиентский и серверный код и поддерживает unary, client-streaming, server-streaming и bidirectional-streaming вызовы. Основной стек использует HTTP/2, а Protobuf является стандартным форматом, хотя сам framework допускает и другие content types.
Он удобен для внутренних типизированных интерфейсов, но требует дисциплины вокруг deadlines, cancellation, retries и совместимости схем. Бинарный payload хуже читается глазами, зато есть специализированные инструменты вроде grpcurl и server reflection.
Нельзя обещать, что gRPC всегда быстрее JSON/HTTP в заданное число раз. Это проверяется на реальном payload, библиотеках, сети и профиле вызовов. Для внешнего браузерного API также нужно учитывать gRPC-Web или gateway и возможности инфраструктуры между клиентом и сервером.
Как я выбираю подход
Вместо таблицы «лучший протокол» я отвечаю на вопросы:
- Кто потребитель и какие технологии он реально поддерживает?
- Взаимодействие естественно описывается ресурсом, процедурой или запросом к графу?
- Нужны ли streaming и двунаправленный обмен?
- Как будет эволюционировать контракт и сколько версий поддерживается?
- Какие прокси, gateways и средства диагностики стоят на пути?
- Каковы требования к latency, размеру payload и нагрузке — по измерениям?
- Кто владеет API после релиза?
Надёжность не выбирается названием протокола. Таймауты, повторы, идемпотентность, backpressure и согласованность данных проектируются отдельно.
Семь пунктов ревью спецификации
1. Операции и семантика
Понятно ли, что является чтением, командой или созданием ресурса? Можно ли безопасно повторить запрос после таймаута?
2. Ошибки
Есть ли стабильные машинные коды, человекочитаемое описание, correlation ID и разделение клиентских и серверных ошибок?
3. Совместимость
Версия в URL — лишь один вариант. Можно использовать media type, заголовок или эволюционировать один контракт совместимыми изменениями. Важна политика: что считается breaking change и как проходит deprecation.
4. Пагинация и лимиты
Большие коллекции требуют ограничений. Offset pagination проста; курсор на устойчивом ключе сортировки помогает избежать части пропусков и дублей при изменениях. Само слово cursor не гарантирует согласованный снимок. Контракт должен задавать максимальный размер страницы, стабильный порядок с разрешением равенств и поведение при изменении данных между запросами.
5. Сбои и повторы
Нужны timeout, правила retry, idempotency key для неидемпотентных операций и поведение при частичном успехе.
6. Безопасность данных
Контракт фиксирует схему аутентификации, авторизацию, чувствительные поля и запрет на утечку секретов в URL и логи.
7. Наблюдаемость
Нужно заранее договориться о request/correlation ID, метриках ошибок и latency, а также о владельце алертов.
Практика на Telegram-боте
На курсе я давал студентам задание собрать Telegram-бота на Flask. Webhook приносит POST с JSON, приложение проверяет входные данные и отправляет ответ через Telegram Bot API.
Небольшой проект заставляет пройти весь контракт: HTTP-методы, JSON, токен, timeout, ошибки и повторная доставка update. Теория быстро становится конкретной — запрос либо проходит по согласованному сценарию, либо нет.
Системному аналитику важно не заучить список технологий, а уметь прочитать спецификацию и найти недоговорённости до разработки. Формат даты, nullable-поле, лимит страницы и повтор после таймаута выглядят мелочами только до первого несовместимого клиента.
Для проверки семантики полезны первичные источники: RFC 9110, SOAP 1.2, GraphQL over HTTP и документация gRPC.
Оригинал статьи: API от А до Я на Habr
Ваш ДПУПП
Похожие статьи
AI в разработке: где он ускоряет работу, а где создаёт новый риск
Практика разработки с AI: выбор моделей под задачу, тарифы на 19 октября 2026 года, локальное развёртывание и проверка готового продукта.
Analyst Days 16: Узри, падаван, путь данных
Реконструкция ключевых идей доклада Analyst Days 16: как данные получают контекст, почему роли видят один набор по-разному и что аналитику важно проверять.
Analyst Days 14: Не крась траву — риски данных в BANI-мире
Реконструкция доклада Analyst Days 14 о качестве и владении данными: как отличить рабочий процесс от красивой отчётности.