Ресурсы, методы и коды состояния — Примеры
Пример 1 — Возврат — это ресурс
Команде поддержки нужен способ вернуть деньги за заказ, и первый черновик добавляет операцию в путь заказа и сообщает результат одним кодом успеха. Перепишите запрос и ответ так, чтобы адрес обозначал вещь, статус говорил, что произошло, а клиент мог найти возврат, не угадывая.
POST /orders/refundOrder
{ "order_id": 42, "amount": "12.50" }
200 OK
{ "success": true }
Решение
POST /orders/42/refunds
Idempotency-Key: refund-42-1
{ "amount": "12.50", "reason": "damaged" }
201 Created
Location: /orders/42/refunds/7
{ "id": 7, "order_id": 42, "amount": "12.50", "status": "pending" }
Теперь возврат — вещь, принадлежащая заказу: адрес говорит, что было создано, а не какое действие выполнено, статус сообщает, что новый ресурс существует, а заголовок location несёт его адрес, поэтому клиент ни опрашивает сервер, ни конструирует идентификатор. Однако черновик возвращает один и тот же код успеха и когда возврат принят, и когда заказ уже был возвращён, — и каждый клиент вынужден делать особый случай. Обычно ошибаются с чтением, которое меняет состояние: такое чтение выполнит предзагрузчик.
Пример 2 — Повтор, который не должен вернуть деньги дважды
Клиент перестал ждать ответа о возврате и отправил запрос снова, сервер создал второй возврат, и клиенту заплатили дважды. Журнал ниже — из того дня. Напишите запрос и поведение сервера, которые делают повтор безопасным.
14:02:11 POST /orders/42/refunds 201 id=7
14:02:11 ...клиент дождался тайм-аута, ответ так и не пришёл
14:02:12 POST /orders/42/refunds 201 id=8
14:02:12 тревога: заказ 42 возвращён дважды (иллюстративно)
Решение
14:02:11 POST /orders/42/refunds
Idempotency-Key: refund-42-1 201 id=7
14:02:12 POST /orders/42/refunds
Idempotency-Key: refund-42-1 201 id=7
сервер записывает ключ вместе с первым результатом и возвращает его без изменений
Клиент передаёт ключ, который обозначает попытку, а не момент времени; сервер хранит ключ рядом с результатом, поэтому вторая доставка возвращает первый исход и ничего не записывает, — и тайм-аут можно считать неизвестным, а не фатальным. Обычно ошибаются иначе: ключ генерируют на каждую попытку, из-за чего повтор всякий раз выглядит новой работой.