Pull to refresh

Comments 16

Пример: {[«a», «b»]}

А зачем возвращать невалидный JSON?

Для идентификаторов используйте UUID

Не думаю, что это является частью проектирования REST API

На счет ошибок: предпочитаю разделять ошибки транспорта от ошибок бизнеспроцесса.
Т.е. если транспорт (http) доставил запрос от клиента серверу и обратно доставил ответ сервера - то http-status=200 независимо от содержимого ответа сервера.
Мотивация:
- путь запроса большой и 503 может отдать nginx посередине. Искать такие ошибки - боль.
- в качестве транспорта может быть использован не только http (я видел АПИшку работающую и на UDP, и на RabbitMQ, пробовали даже принтер со сканером использовать но неудачно)

А 4xx не должен nginx выдавать кроме 404. Так почему бы не совмещать этот блок с блоком json, где детально расписать ошибку?

Правильно ли я понял, что на запрос с истекшим токеном, с невалидными входными данными, с не найденным объектом, etc, вы возвращаете 200? О_о

Невалидные данные - это не проблема транспорта. Он доставил запрос и обратно ответ без ошибок со своей стороны.

Не забываем, что мир одним только http не ограничивается. Приводя мой пример выше: мы активно использовали WinSocket для взаимодействия между СИшными либами, а там как вы понимаете нет никаких http-status. При этом эту же библиотеку применяли для межсервисного взаимодействия по http и UDP (для броадкаста, хотя позже на кроликов перевели)

Разумеется, т.к. ничего из этого не является частью протокола HTTP (транспортного слоя, как очень правильно отметил @XMack), а исключительно бизнес-логикой приложения. По этой причине REST в его "прямом" смысле - крайне отвратительная методология.

А всего лишь надо стандартизировать ответ ошибки, чтобы он включал в себя имя точки отказа и кодифицированную причину ошибки. В теле или заголовках.

Согласитесь, поведение клиента сильно отличается в случае ответа Too many requests, и в случае ответа Unauthorized.

А для бизнес-ошибок лучше возвращать 422 Unprocessable Entity.

здесь как вам удобно)

моя мысль в том, что крайне полезно сразу в спецификации видеть допустимые бизнес-ошибки и иметь их справочник. И всегда придерживаться одного подхода.

Я в основном имею дело с вэбом, и идея 200 ОК - {"error": "user_not_found"} контринтуитивна, и вызывает так сказать эмоции. Потому что я не ожидаю такое увидеть, и мне нужно тратить лишнее время чтобы понять подход и задумку. Потому что для меня ошибки транспорта обычно не связаны с архитектурой моего приложения, или легко локализуются (через поля c указанием сервиса-источника исключения). Но я допускаю, что могут быть задачи, где такой подход ок, наравне как и подход POST-API например. Но каждый из подходов сам в себе не регламентирует описание именно бизнесовых ошибок, тем более что они еще и по ходу пьесы всплывают частенько и не добавляются в спецификации. Повторюсь, я за полный справочник ошибок, их формальную привязку к месту возможного появления, и консистентность в выбранном подходе.

Например, используйте iso-8601 YYYY-MM-DDThh:mm:ss±hh.

OpenAPI поддерживает RFC 3339, section 5.6. Если не нужны специфичные фишки из iso8601 (периоды или интервалы дат, например), то лучше выбрать первый. А тут можно наглядно увидеть разницу https://ijmacd.github.io/rfc3339-iso8601/

UUID — это стандарт идентификации, используемый в создании программного обеспечения Основное назначение UUID — это позволить распределённым системам уникально идентифицировать информацию без центра координации.

Тут есть как плюсы так и минусы, поэтому всегда так делать не стоит, нужно оценивать ситуацию. Если объект в бд хранится и по полю с идентификатором есть кластеры индекс, то лучше использовать монотонно возрастающие идентификатор от сиквенса. Так при вставке не придётся постоянно пересортировывать таблицу в бд.

Также генерация UUID более затратна и если нужно для массовой операции сразу 1000 идентификатор сформировать, то это можно сделать только последовательно дернув 1000 раз функцию получения UUID, а у сиквенса можно сразу диапазон запросить за один вызов.

по умолчанию, для меня плюсы uuid перевешивают недостатки, поэтому я беру его. В случае, когда нужно оценивать ситуацию, я скорее начну рассматривать варианты использования ulid или какого-нибудь ksuid (совместимые с uuid), нежели обычного инта из сиквенса)

Даже если int занимает 4 байта, а UUID 16? Особенно в сложных системах, где много таблиц нормализованных и много связей между ними по идентификатора. Да ещё и с индексами по этим идентификаторам.

Тут накладные расходы на хранение идентификатором могут быть значительными, всегда ли оно того стоит?

Есть популярный совет - не раскрывать в API идентификаторы из вашего хранилища. В таком случае, что показывать снаружи и что использовать внутри это два разных вопроса. Ответы на которые с течением времени могут меняться независимо друг от друга.

в теории хранение под uuid в 4 раза большего места выглядит значительно. На практике это не имеет решающего значения, т.к. помимо идентификаторов в моделях обычно хранятся на порядок больше полезных данных и относительный вклад небольшой. я не помню проблем из-за того, что размер базы сам по себе просто "очень большой", или индекс по полю c uuid работает медленнее интового. Если прям нужно экономить место, ну или вы видите явные преимущества данного типа - используйте конечно. Но не забудьте еще учесть возникающие сайд эффекты - проверьте API на возможность прямого доступа без проверки владения ресурсом, ну и вероятность мержа этой таблицы с какой-то другой из третьего источника в будущем. По мне проще, переплатить сразу местом хранения, чем читать новости про очередную слитую базу, в данном случае из-за банального недосмотра прав доступа и инкрементальных id)

Sign up to leave a comment.