В личном кабинете заказ получил статус «Принят». Но что это означает: запись появилась на сервере, менеджер взял её в работу или товар уже зарезервирован? Если две системы понимают слово по-разному, красивый интерфейс не спасёт обмен данными.
В Гуси-Лебеди мы предлагаем разбирать API через такие вопросы. Ниже используем условный сервис заказов, чтобы показать, что нужно согласовать между приложениями. Это учебный пример, а не описание выполненного проекта компании.
Ресурс, адрес и представление: что именно получает приложение

API задаёт интерфейс взаимодействия программ. REST API называют интерфейс, построенный по архитектурным ограничениям REST. Это не отдельный язык программирования или формат файла. Исходная модель изложена в диссертации Роя Филдинга. Поэтому наличие JSON и нескольких адресов ещё не доказывает соответствие REST.
Возьмём заказ с идентификатором 42. В нашем условном интерфейсе адрес /orders/42 обозначает этот ресурс. Адрес обращения к API также называют эндпоинтом, или endpoint. Приложение получает представление заказа: например, номер, состав и текущий статус. Представление не обязано совпадать со строкой базы данных. Поля, которые нужны бухгалтерии или внутренней диагностике, не становятся доступными клиенту только потому, что они существуют в системе.
Отдельно договоритесь о смысле статуса. «Принят» может обозначать конкретный этап обработки, установленный разработчиками сервиса. Клиентскому приложению нужно знать этот смысл и доступные следующие действия. Иначе оно может показать обещание, которого сервер не подтверждал. Такие правила стоит согласовать при разработке серверной логики, пока интерфейс и обработка заказа ещё проектируются.
В исходной модели REST единообразный интерфейс включает идентификацию ресурсов, работу через представления, самодостаточные сообщения и гипермедиа для переходов между состояниями. Это шире таблицы «адрес плюс метод». При обсуждении проекта полезно спросить, как клиент узнаёт о связанных объектах и допустимых действиях, а не просто назвать любой HTTP-интерфейс RESTful.
Stateless означает, что запрос содержит необходимую информацию для обработки без опоры на сохранённый контекст клиентской сессии. Это не запрет хранить заказы на сервере. Сам заказ сохраняется и меняется; ограничение относится к организации взаимодействия клиента и сервера.
Метод запроса: чтение и изменение требуют разных договорённостей

Адрес ресурса сам по себе не объясняет действие. В условном сервисе GET /orders/42 запрашивает представление заказа, а POST /orders передаёт данные для обработки, которая по нашему контракту создаёт новый заказ. POST не означает создание при любых обстоятельствах: его назначение шире, как показывает справочник MDN. В таблице ниже приведены пять методов HTTP, полезных для разбора этого примера, а не полный перечень методов протокола.
При чтении документации смотрите на метод вместе с адресом, параметрами, заголовками и телом. Параметр пути может выбирать конкретный заказ, параметр запроса может задавать фильтр списка. Заголовки сообщают дополнительные условия обмена, а тело содержит передаваемые данные, если оно предусмотрено для операции. Не заменяйте это описание одной строкой «принимает JSON».
| Метод | Что означает стандартная семантика | Что уточнить для заказа |
|---|---|---|
| GET | Получить представление ресурса | Какие поля видит клиент и насколько свежи сведения. |
| POST | Передать данные на обработку | Создаётся ли заказ и как получить его идентификатор. |
| PUT | Заменить представление целевого ресурса | Какие данные передаются целиком и что происходит с пропущенными полями. |
| PATCH | Внести частичные изменения | Формат изменений и разрешённые переходы состояния. |
| DELETE | Удалить ресурс согласно семантике интерфейса | Что происходит с доступностью заказа и связанной историей. |
Особенно внимательно разберите повтор запроса. Клиент отправил данные заказа, соединение оборвалось, ответ не пришёл. Из этого нельзя сделать вывод, что сервер не успел создать запись. Слепой повтор POST может создать второй заказ. Если сервис предусматривает защиту от дублей, её условия должны быть описаны: как узнаётся повтор, сколько действует идентификатор операции и какой результат возвращается.
Идемпотентность относится к предполагаемому эффекту одинаковых запросов на сервере: несколько повторов дают тот же эффект, что один запрос. По стандартной семантике PUT и DELETE идемпотентны, POST и PATCH такой общей гарантии не имеют. Ответы при этом могут различаться. Разницу объясняет MDN об идемпотентности. Для конкретного API нужно проверить, соблюдает ли реализация заявленное поведение.
Ответ сервера: «принято» ещё не всегда означает «выполнено»

Если сервер возвращает 202 Accepted, запрос принят для обработки, но обработка ещё не завершена и её успех не гарантирован. Это значение кода 202, а не ошибка. В нашем условном сервисе клиенту понадобился бы отдельный способ узнать результат: например, предусмотренный контрактом адрес проверки операции.
Поэтому согласуйте, что интерфейс может сказать человеку сразу. «Запрос принят, проверяем наличие товара» и «Товар зарезервирован» обещают разные результаты. Сообщение должно следовать из фактического этапа обработки, а не из удобного текста для зелёного уведомления. Как показывать ожидание и ошибки человеку, разбираем отдельно в статье о состояниях интерфейса сайта.
Полный ответ включает больше, чем код: важны заголовки и предусмотренное тело. Для заказа договоритесь о значении полей, допустимых статусах и ситуации, когда данных пока нет. Если пользователь должен исправить ввод, ответу полезно указывать конкретное поле и причину. Временная недоступность сервиса требует другого поведения клиента.
Не помещайте секреты и внутренние подробности защиты в сообщение, которое увидит пользователь. Для обсуждения ошибки с поддержкой можно предусмотреть идентификатор запроса и сопоставление с журналом сервиса. Состав журнала выбирается под проект, а не копируется вместе с чужим примером ответа.
Как проверить контракт до подключения рабочего клиента

Начните с документации установленной версии и тестового окружения. Клиентскому разработчику нужны адреса, методы, обязательные поля, способы аутентификации, ограничения доступа и примеры ответов. Но удобная документация ещё не доказывает, что сервер ведёт себя именно так. Описание нужно сопоставить с фактическими запросами на согласованных тестовых данных. Если подключаете чужой сервис к своему сайту, учитывайте также владельцев данных и порядок обмена: этому посвящён разбор подключения систем через API.
Для нашего заказа сначала проверим обычный путь: передали допустимые данные, получили идентификатор, запросили созданный ресурс и увидели согласованный статус. Затем намеренно пропустим обязательное поле. Клиент должен получить объяснимый отказ, а не ложное сообщение об успешном оформлении. Проверку удаления проводим только на специально созданном тестовом объекте, чтобы не затронуть рабочую историю.
Другой важный сценарий связан с правами. Участник проверки видит свой заказ; отдельно команда проверяет, что доступ к чужому объекту ограничен согласно правилам проекта. Нельзя считать защиту достаточной только потому, что чужая карточка скрыта в интерфейсе: ограничение должно действовать на стороне сервиса. Способ и объём такого испытания согласуют для разрешённого тестового окружения.
Повторные запросы требуют отдельного сценария. Проверьте не только одинаковое тело, но и предусмотренный идентификатор операции, если сервис его использует. Заранее определите, как отличить повтор прежней попытки от нового заказа с похожими данными. Результат испытания сохраняйте вместе с версией сервиса, условиями, ожидаемым поведением и фактическим ответом.
До выпуска изменений обсудите совместимость. Новое поле, переименование статуса и удаление адреса могут по-разному затронуть клиентов. Не обещайте, что любое добавление поля безопасно: некоторые приложения строго проверяют структуру ответа. Полезнее определить поддерживаемые версии, порядок уведомления и период перехода, если он требуется проекту.
В Гуси-Лебеди мы советуем принимать API по завершённому сценарию. Приложение понимает, к какому ресурсу обращается, выполняет разрешённое действие, корректно реагирует на ответ и не выдаёт ожидание за готовый результат. Если планируете создание веб-сервиса, начните обсуждение именно с таких сценариев. Тогда у команды есть предметная договорённость о работе сервиса, а у пользователя понятный следующий шаг.
