409 Conflict в API

The request could not be completed due to a conflict with the current state of the target resource. This code is used in situations where the user might be able to resolve the conflict and resubmit the request.

Часто при дизайне API забывают о 409. Если в описании интерфейса пропущен этот код ошибки, то это очень сильный сигнал к тому, что в API есть гонки.

Упрощенный пример с гонкой:
Обновления состояния какого-то объекта

POST update_something?new_value=

Пример почему так делать может быть плохо:

Есть endpoint, который управляет скидками в сервисе: флаг включения скидки и размер самой скидки

POST update_discount?enable=[OPTIONAL]&value=[OPTIONAL]

2 человека, которые видят в веб-интерфейсе одно и то же начальное значение: {enable=false, value=0}.

Один из них хочет изменить {enable=true}, понимания, что новое значение не поменяет поведения, потому что размер скидки установлен 0.
Вызывает POST update_discount?enable=true

Другой хочет установить value=30 и только через какое-то время включить саму скидку.
Вызывает POST update_discount?value=30

Оба не хотели делать так, чтобы скидка включалась сейчас, однако, последовательность действий привела к обратному.

В хорошем интерфейсе клиент должен понимать, что конкретно он меняет и на что.

Одним из хороших вариантов тут — иметь версию изменяемого объекта. Если версия по каким-то причинам изменилась на бэкенде, то самое время вспомнить про 409 ошибку.

Как может выглядеть интерфейс:

POST update_discount?enable=[OPTIONAL]&value=[OPTIONAL]&version=[REQUIRED]

Клиент явно передает номер версии объекта, который он меняет. Если версия на бэкенде почему-то отличается от той, что присылает клиент, то нужно вернуть 409, чтобы клиент обновил более актуальную версию. В каких-то веб-интерфейсах пользователи часто видят «Версия документа устарела, обновить».