Прошу прощения, что поднимаю старый топик, но давно хотел спросить, а всё как-то было не у кого...
А для чего в практическом плане возвращать разные положительные коды? RD>200 (OK) — все OK, в теле ответа будут данные RD>201 (Created) — все ОК, новая сущность создана. Обычно в ответ на POST, в хидере Location — адрес новой сущности. В теле ответа могут быть данные. RD>202 (Accepted) — все ОК, мы твой запрос приняли, обработаем позже (e.g. положили в очередь). В теле ответа могут быть данные. RD>204 (No Content) — все ОК, мы твой запрос обработали, но контент вернуть не можем (обычно в ответе на DELETE)
Чем это удобнее, в сравнении с возвращением всегда ровно одного кода, того же 200 и всё?
Т.е. мне представлялось, что какой именно положительный результат мы получим (можем получить) — понятен уже из контекста. Если мы вызывали метод создания — то результатом и должно быть создание, а при удалении контента не будет, и т.д.
Различать может быть полезно в случаях вроде "'вернуть' или 'создать новый и вернуть'", но и то, вроде как не критично нужный случай...
Здравствуйте, GarryIV, Вы писали:
vsb>>Не согласен. Если я забыл задеплоить варку, у меня внезапно куда-то исчезли все юзеры? Не так ведь.
GIV>Вот это и надо фиксить если уж на то пошло, 503 вполне подойдет.
Ну а как ты это пофиксишь, весь серверный софт так работает: апач, нджинкс, томкат. Никогда не видел, чтобы по дефолту кидалось 5xx.
Здравствуйте, vsb, Вы писали:
vsb>Ну а как ты это пофиксишь, весь серверный софт так работает: апач, нджинкс, томкат. Никогда не видел, чтобы по дефолту кидалось 5xx.
Например спереди стоит haproxy и форвардит реквесты только если health check урл возвращает ожидаемые данные.
Попробую.
Прежде всего, идеологически это соответствует описанию статус-кодов HTTP-протокола.
И там много чисто HTTP-шных нюансов. Например, 200 ответы по-умолчанию кэшируется, а 201/202 — нет.
Кроме того, клиенту никто не мешает просто интерпретировать любой 2xx код как успешный.
С практической же точки зрения, попробую объяснить на примерах:
1. 200 vs 202 (Accepted)
POST /api/payments { id, amount, operationType }
Сервер в зависимости от параметров платежа (сумма, тип) и текущего состояния системы (высокая нагрузка, конкретный провайдер платежа лежит и т.п.) может либо исполнить платеж сразу, либо отложить его на потом.
Поэтому:
200 OK — исполнили сразу, результат вернули, его можно сразу прочитать и отобразить пользователю.
202 Accepted — приняли к исполнению, исполним позже. Клиенту можно не читать body, а сразу идти на GET /api/payments/{id} и проверять статус там.
2. 200 vs 201 (Created)
POST /api/payments { id, amount, operationType }
ID платежа определяет клиент (скажем, это GUID).
А мы со своей стороны гарантируем идемпотентность операции создания, т.е.
мы говорим: "если ты будешь пытаться создать платеж с одним и тем же id много раз, то для нас это нормально".
По HTTP протоколу POST запросы не идемпотентные, но это бывает нужно, если, например у нас слабый канал и клиент реализует какую-то политику ретрая.
Или клиент пропихивает платежи из своей системы в нашу в несколько потоков/процессов.
В этом случае:
201 (Created) — клиент уверен, что это именно он создал платеж. Можно, например, обновлять балансы в своей локальной системе.
200 OK — такой платеж уже есть, но его создали не мы. Просто игнорируем.
Если бы мы возвращали чисто 200, нам бы пришлось как-то менять модель платежа (добавлять какие-то доп. поля/признаки) для обработки такой ситуации, что как-то не очень чисто.
3. 200 vs 204 (No Content)
POST /api/articles/{id} => [ content ]
Допустим мы пишем редактор постов на wiki для такой API-шки (POST соответствует сохранению).
Тогда у нас возможны варианты:
200 OK — твои данные сохранились. Но, похоже, кто-то делал изменения в других частях статьи, и мы их смержили. Прочитай новое тело статьи из тела ответа и обнови UI.
204 OK — твои данные сохранили. Статья на сервере такая же, как локальная, поэтому контента мы тебе не шлем.
Здравствуйте, RushDevion, Вы писали:
RD>2. 200 vs 201 (Created) RD>POST /api/payments { id, amount, operationType } RD>ID платежа определяет клиент (скажем, это GUID). RD>А мы со своей стороны гарантируем идемпотентность операции создания, т.е. RD>мы говорим: "если ты будешь пытаться создать платеж с одним и тем же id много раз, то для нас это нормально". RD>По HTTP протоколу POST запросы не идемпотентные, но это бывает нужно, если, например у нас слабый канал и клиент реализует какую-то политику ретрая. RD>Или клиент пропихивает платежи из своей системы в нашу в несколько потоков/процессов. RD>В этом случае: RD>201 (Created) — клиент уверен, что это именно он создал платеж. Можно, например, обновлять балансы в своей локальной системе. RD>200 OK — такой платеж уже есть, но его создали не мы. Просто игнорируем.
это явный 409 Conflict. и ни в коем случае не 200 ОК.
Здравствуйте, RushDevion, Вы писали:
RD>201 (Created) — клиент уверен, что это именно он создал платеж. Можно, например, обновлять балансы в своей локальной системе. RD>200 OK — такой платеж уже есть, но его создали не мы. Просто игнорируем.
Вот это не очень удачная идея. Лучше возвращать 409, а не 200.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Вот это не очень удачная идея. Лучше возвращать 409, а не 200.
Это если параметры платежа отличаются от того, который записан в системе.
А если совпадают — то 200.
Потому что иначе клиент не может понять, принят ли вообще его платёж, или нет.
В более простом случае: бронируем место в самолёте. Отправляем: "Вася сядет на место 15С".
Если мы получаем 4хх, то мы должны сказать Васе: "извини, не получилось". Конкретно для 409 — "пока мы с тобой тупили, кто-то уже сел на 15С".
Если клиент получил 409 не с первого раза, то он не знает, доходили ли до сервера его предыдущие запросы — т.е. не может отличить ситуацию конликта с самим собой от конфликта с кем-то ещё.
Поэтому если мы получаем такой запрос, а в системе уже записано, что Вася сидит на месте 15С, то мы отдаём 200 — это требование идемпотентности. Мы же не знаем, увидел ли Вася наши предыдущие ответы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, S>Поэтому если мы получаем такой запрос, а в системе уже записано, что Вася сидит на месте 15С, то мы отдаём 200 — это требование идемпотентности. Мы же не знаем, увидел ли Вася наши предыдущие ответы.
А может в этом случае стоит возвращать 208 already reported? И не ошибка и известие, что место уже было для вас забронировано.
Здравствуйте, KOLRH, Вы писали:
KOL>Здравствуйте, Sinclair, S>>Поэтому если мы получаем такой запрос, а в системе уже записано, что Вася сидит на месте 15С, то мы отдаём 200 — это требование идемпотентности. Мы же не знаем, увидел ли Вася наши предыдущие ответы.
KOL>А может в этом случае стоит возвращать 208 already reported? И не ошибка и известие, что место уже было для вас забронировано.
Я бы удивился, получив такой респонс.
Его штатное применение — совсем другой сценарий:
The 208 status never appears as a true HTTP response code in the status line, and only appears in bodies.
Здравствуйте, Sinclair, Вы писали:
S>Потому что иначе клиент не может понять, принят ли вообще его платёж, или нет.
Обычно передают некий request id, а не сравнивают поля. И возврат 409 вполне однозначно указывает на то, что запрос с таким id уже обработан.
S>Поэтому если мы получаем такой запрос, а в системе уже записано, что Вася сидит на месте 15С, то мы отдаём 200 — это требование идемпотентности.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Обычно передают некий request id, а не сравнивают поля.
Придётся делать и то и то. НС>И возврат 409 вполне однозначно указывает на то, что запрос с таким id уже обработан.
Нет, так делать нельзя. Что вы будете возвращать в ответ на запрос, который конфликтует с результатом другого запроса с другим id?
S>>Поэтому если мы получаем такой запрос, а в системе уже записано, что Вася сидит на месте 15С, то мы отдаём 200 — это требование идемпотентности. НС>POST неидемпотентен по спеке.
Поэтому надо делать PUT.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
НС>>Обычно передают некий request id, а не сравнивают поля. S>Придётся делать и то и то.
Зачем?
НС>>И возврат 409 вполне однозначно указывает на то, что запрос с таким id уже обработан. S>Нет, так делать нельзя. Что вы будете возвращать в ответ на запрос, который конфликтует с результатом другого запроса с другим id?
400. Либо можно возвращать конкретную причину в теле 409. Главное — вся эта котовасия должна отрабатываться на уровне мидлвера и retry policy, а не лезть в BL.
S>>>Поэтому если мы получаем такой запрос, а в системе уже записано, что Вася сидит на месте 15С, то мы отдаём 200 — это требование идемпотентности. НС>>POST неидемпотентен по спеке. S>Поэтому надо делать PUT.
Про PUT совсем другой разговор, там свои заморочки. И вот там то как раз нужно полное сравнение всех полей.
Здравствуйте, MadHuman, Вы писали:
MH>Здравствуйте, Ночной Смотрящий, Вы писали:
MH>>>если сервера — 500 (это перегрузка сервера НС>>Для перегрузки есть специальный код, 429. MH>да, но 429 (Too Many Requests) — для более узкого случая, когда хотят на сервере ограничить частоту реквестов от клиента. в этом случае да, лучше его. MH>я имел ввиду несколько другие ситуации, например для обработки реквеста надо сходить в базу, база перегружена и ответила соотвествующей ошибкой. MH>или сервер под высокой нагрузкой и реквест клиента по каким-то причинам (особенно связанным с данными клиентам) выполняется слишком долго и его прервали. MH>или сервер уже под высокой нагрузкой и пока лучше не начинать обработку новых запросов. MH>типа такого.
Здравствуйте, Буравчик, Вы писали:
Б>Какие HTTP status code используются в ваших API? Б>200, 401, 403, 404 и т.п.
Добавил бы 201 — Created со ссылкой на созданный ресурс в заголовке Location. 201-created полезен на случай когда клиент что-то создает и нужен переход на созданный ресурс (мало-ли пользователь захочет еще что-то отредактировать).
И 204 — No Content. Все ок, но контента нет. Полезен для ответов на Delete, на пример.
Иногда приходилось использовать 409 — Confilct для того, что бы показать, что модифицированные пользователем данные были изменены ранее.
Б>Передаете ли дополнительную информацию об ошибках? Какую? Б>Код ошибки, текстовое сообщение, на каком языке (русский, английский), дополнительные параметры?
json: {code: <литеральный код ошибки>, message: <сообщение для разработчиков>, description: <пояснение ошибки и что надо сделать, что бы ее не получить для разработчиков>}.
Разработчики клиентской части уже обрабатывают коды ошибок. Текс ошибок и пояснение им нужны в отладке Rest API через swagger. Тестировщикам для локализации багов тоже будет полезно получать текст ошибок и описание.
Б>Кодируете ошибки, как? Единая нумерация для всего API, или свои ошибки для каждого endpoint?
Просто литералы. Который указываешь в описании API.
Б>Используете какие-то правила для возвратов ошибок? Б>Например, по аналогии с JSON-RPC, в котором наличие в ответе поля errors означает, что произошла ошибка при обработке запроса.
На клиенте? Проверяешь http.status
Б>Что возвращаете, если клиент запрашивает существующий ресурс, к которому запрещен доступ: Б>404 или 403?
Лучше все-таки различать 403 — Forbidden & 404 — Not Found. Будет меньше вопросов у клиентов.
Возможно, что в некоторых случай помимо 404, можно вернуть 410 — Gone. Если на клиенте кешируются ресурсы и идет запрос на обновление этого ресурса, которого уже нет на сервере, то имеет смысл вернуть 410, хотя, если вернуть 404 — это тоже небольшая проблема. Просто 404 говорит о том, что ресурс не найден, но возможно потом он будет доступен. А вот если ресурс был, но теперь ушел и больше не вернется, то 410.
Б>В общем, научите как надо возвращать информацию об ошибках в API
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Уникальный код, severity, источник, нелокализуемое сообщение на английском, название параметра если применимо, значения подстановок для локализованного сообщения. В отладочных версиях еще stacktrace.
На мой взгляд, лучше делать так, что бы StackTrace ни когда не покидал бы сервер
Тогда не возникнет гипотетическая ошибка, по которой и на проде, stacktrace уйдет клиенту
Нормальный вариант логировать stacktrace, логи смотреть через http с авторизацией.
Здравствуйте, white_znake, Вы писали:
_>На мой взгляд, лучше делать так, что бы StackTrace ни когда не покидал бы сервер _>Тогда не возникнет гипотетическая ошибка, по которой и на проде, stacktrace уйдет клиенту
Если это в одном месте настраивается, то не возникнет.
_>Нормальный вариант логировать stacktrace, логи смотреть через http с авторизацией.
Логи обычно доступны только владельцам сервиса, а вот стектрейс часто полезен тем, кто использует отладочные версии.