Pull to refresh

Comments 207

Хранить CSRF токен в куках плохо по той причине, что куки можно украсть, в чём собственно и состоит суть CSRF атаки.

Поправьте меня если я ошибаюсь, но суть CSRF не в воровстве куков. Если мы можем украсть куки, то нам не страшны никакие CSRF токены, потому что мы просто будем использовать куки, а токен нам пришлет сервер.

Не совсем так. GET и POST запросы можно подделать средствами чистого HTML, GET так вообще картинкой (типа <img src="..."), например, в почте (email fishing). И запрос будет выполнен браузером с текущими куками юзера. С POST чуть сложнее, не все емейл-клиенты пропустят форму, плюс нужна активная реакция от юзера, но всё равно можно. PUT и прочие запросы можно запилить только на js, который в большинстве случаев будет надёжно зарезан.
CSRF токен при грамотной реализации позволяет защититься от атак типа вставки картинки в письмо. Но как его грамотно реализовать? Если мы лепим его в куку или в параметр (т.е. в url для get), то токен должен протухать при каждом новом запросе, что не очень удобно, когда клиент запускает запросы асинхронно целыми пачками. Передача дополнительного заголовка позволяет продлить жизнь токенам, плюс требует обязательного использования javascript или иного кода клиентом. И при этом может спасти, даже если клиенту подсунули трояна с curl, имеющего возможность прочитать живую куку прямо с диска.

Я говорил не про важность использования CSRF в целом, а про конкретную цитату


куки можно украсть, в чём собственно и состоит суть CSRF атаки.

Для эксплуатации CSRF нет необходимости красть куки.


CSRF токен при грамотной реализации позволяет защититься от атак типа вставки картинки в письмо.

То есть атаку на GET? Если GET не меняет состояние, то CSRF для него не нужен.


И при этом может спасти, даже если клиенту подсунули трояна с curl, имеющего возможность прочитать живую куку прямо с диска.

Но как? У нас есть кука, которую достали трояном. Мы с этой кукой идем на сайт и все, никакой CSRF токен нам больше не нужен.

То есть атаку на GET? Если GET не меняет состояние, то CSRF для него не нужен.


Нужен, если передаются конфиденциальные данные, которые мы не хотим отдавать кому попало.

Но как? У нас есть кука, которую достали трояном. Мы с этой кукой идем на сайт и все, никакой CSRF токен нам больше не нужен.

Идёте на сайт со свежеворованной кукой и на любой, в том числе get запрос получаете 419 Authentication Timeout, потому как CSRF токена у вас нет. Для продолжения работы вам нужно ввести пароль, который трояну украсть негде.
Украсть живой токен конечно тоже можно, но уже значительно более сложным трояном (со сниффером и подделкой https сертификатов или чтением памяти браузера).
Нужен, если передаются конфиденциальные данные, которые мы не хотим отдавать кому попало.

А каким образом "кто попало" их получит? Рассмотрим ту же картинку с запросом, пришедшую на почту. Для пользователя она будет просто незагрузившейся картинкой, а злоумышленник её вовсе нигде не увидит.

Не понятно. Тогда всякие там контактики и хабры должны меня выкидывать на авторизацию при переоткрытии браузера, а такого не происходит.
Спертой куки хватит для авторизации, но не всегда есть возможность ее прочитать, иногда можно только вслепую ей воспользоваться (та самая картинка). И вот тут уже приходит CSRF токен в месте c Referer, которые тупо не дают сходу выполнить любой значимый запрос, кроме инициализации новой сессии (предъявляем куки) с получением CSRF токена. Как-то так.
Зависит от деталей реализации проверок CSRF и общего уровня садизма разрабов. При смене региона айпишника вконтактик вас выкинет и ещё и 2FA заставит делать.

Добавьте, пожалуйста, в ваш список: Никогда не передавайте конфиденциальные данные методом GET.


Далее, использование кукис при реализации CSRF Protection — корпоративный стандарт для многих фрэймворков и CMS.

Слабовата аргументация по использованию кодов ответов отличных от 200. Они не просто обрабатываются браузером, что тоже верно, а еще и транспортным слоем (инфраструктурным). Что является ключевым аргументом за REST вообще и релевантные коды в частности.
Вы когда-нибудь пытались сделать клиента к апи, которое на всё подряд кидает 200 ОК? Даже если вы тупо опечатались в запросе, или, самое смешное, сервер падает и не успевает передать ничего, кроме этого самого 200 ОК, которое затем кешируется.
Вы явно не поняли мой посыл — habr.com/ru/post/440900 То, что вами в статье отражено — верно. Но это не все ключевые аргументы в пользу релевантных кодов ответа как и самого выбора REST.
Ну в этом смысле — да.
Во всех смыслах HTTP 200 OK это ответ веб-сервера, а не API, сообщающий клиенту о том, что тело ответа возвращено успешно. Поскольку бизнес-ошибок всегда намного больше, чем HTTP-кодов, то обычно удобнее выделять ошибки в отдельную структуру ошибок. Держать два разных механизма передачи бизнес-ошибок параллельно тоже иногда неудобно, поэтому их вообще можно выделить в один HTTP-код, пусть и отличный от HTTP 200.

Также, как уже вам заметили другие комментаторы, транспортный слой накладывает свои ошибки, поэтому например «404 эндпоинт на целевом application-сервере не поднят» вы никак не отличите от «404 эндпоинт на целевом application-сервере поднят, но ресурс на нём не найден». Ниже пользователь rpiontik спрашивает, какая разница между этими случаями: разница здесь в совершенно разных сценариях обработки этих ошибок.
Вот не верю я в количество бизнес-ошибок, которых всегда намного больше.
Язык С++ как-то обходится 7 типами исключений. В ОС UNIX за 50 лет развития придумали чуть больше 100 кодов ошибок, из которых 2/3 никогда в реальной жизни не используется. Я, конечно, видел иерархии исключений на 1000+ пунктов, только это людям в больших конторах заняться нечем, а оправдывать свою нужность и незаменимость хочется.
В HTTP из коробки 200 кодов (100 4хх и 100 5хх), которые можно использовать. Вот и используйте. Речь именно о цифровых кодах; для конкретного сообщения у вас есть текст ошибки.
Изобретатели велосипедов типа вас и GreenLordUA предлагают, получив в подарок автомобиль, выбить лобовое стекло и запрячь лошадьми. Потому что это ж блин надо учиться водить машину.
Ну если вам не нужен протокол HTTP и вся инфраструктура, которую он предлагает (браузеры, либы, веб-серверы, прокси, балансировщики, PKI наконец) — ну напишите свой бинарный протокол поверх UDP на левом порту, и обрабатывайте ошибки как вам нравится. Делов то. :)
В HTTP из коробки 200 кодов (100 4хх и 100 5хх), которые можно использовать

Неправда, из коробки в стандартном HTTP кодов почти на порядок значительно меньше.

Весело. Почему вы думаете что все ошибки должны иметь сервер-сайд текст сообщения, без кода? И что, чтобы подсветить конкретное поле на форме, я должен парсить этот текст?
Ну если у вас сервер знает, какое конкретно поле должен подсветить клиент, у вас всё ещё есть кастомные заголовки. Ну или можете отдавать на ошибки json.
ясно, спасибо.
При этом описание ошибки, если оно есть, приводится в теле ответа в формате text/plain (без всякого JSON).
Ну или можете отдавать на ошибки json.

Во-во. В целом рекомендации неплохие, но это именно рекомендации — так и подавать надо.

Да, вполне может быть, что вы не сталкивались со сложными бизнес-процессами и Large Enterprise. В SME может быть, да и то мало где. В микросервисной архитектуре на обработке бизнес-ошибок строится огромный кусок оркестрации: перезапустить контейнер, если 404 или пересоздать отсутствующий ресурс, если отдать специальный код а в теле уточнить, что resource not found (это частный микропример, а можно и запустить процесс создания кучи связанных ресурсов, если они связаны в модели и много чего ещё)


Кодов из коробки совсем мало, нет там и близко двухсот, а те что есть никак не маппятся на бизнес-логику, потому что имеют свое назначение и описание.

Как в таком случае отличить 404 Resource not found слоя ппидожения и слоя транспорта. Бизнес требует в первом случае показывать сообщение пользователю чтл ресурс не найден, во втором случае показывать сообщение Что-то пошло не так. Попробуйте позже

При 404 все пошло так. Просто объекта нет. Это осмысленный ответ сервера. Что-то пошло не так, это 500.
Если проще — стой транспорта — нет интернета например в мобильной версии, или накосячили в маршрутизации бэкенда — будет 404, т. к. физически нет такой страницы или она не получена приложением — тут нет сервера, который мог бы отдать 500.

Вовсе не обязательно осмысленный. Представьте ситуацию: есть сайт http://examle.com и его api http://example.com/api. Содержимое сайта отдаётся каким-нибудь nginx, а на обращения к api отвечает бакэнд, но запрос всё равно идёт через nginx.


Теперь если админ ошибётся в настройке nginx — то в течении какого-то времени на любой запрос к api будет выдаваться 404!


Переходим к ситуации номер два. У нас Windows, nginx заменяем на IIS, а запросы к api пусть обрабатывает служба напрямую через HTTP.SYS


Теперь даже в настройке IIS ошибаться не требуется — достаточно перезапустить службу, и пока она перезапускается на запросы к api будет отвечать IIS. Кодом 404.


И да, усложняя пример можно получить в ответ на запрос любой код HTTP кроме 418...

Это все тот же осмысленный ответ — нет обьекта по этому uri. Не понимаю проблемы. Ну нет там его. Какая разница почему?

Очень большая разница. На этом может строиться бизнес-логика. И поэтому важно отличать эти два состояния. Представьте что какой-то сервис делает запрос в другой сервис
GET /api/banned-users/15/
И на основании ответа решает разрешить ли пользователю логин или нет. Если опираться только на статус 404, то в любая непредвиденная ситуация (сломался роутинг, опечатились в адресе апи в коде, эту апи вообще удалили) будет приводить к серьезным багам в бизнес-логике.
Может? Это плохая бизнес-логика, если она может на этом строиться. К каким серьезным багам будет приводить? Поясните. Если нет объекта, его нет. Или у вас вся система будет валиться на том факте, что у вас не оказалось объекта? Ведь это нормально. И если у вас пользователя в БД не окажется — это тоже нормально.

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

Используя REST вы принимаете решение о работе на уровне HTTP протокола. И нужно принимать его таким, какой он есть. Если вы начнете его под себя гнуть, в итоге он нагнет вас. Потому, что это за рамками вашего проекта.

Хотите консистентность — RPC. Но автоматом вы теряете все профиты HTTP.
Да хоть обминусуйте :))) Это ж вы с места не двинетесь. Я уже это проходил. Ниче… пережил :)))
habr.com/ru/post/440900
Это плохая бизнес-логика, если она может на этом строиться.

Что значит плохая бизнес-логика? Что вы будете делать, если в бизнес-логике предусмотренны разные сценарии в зависимости от того существует объект или нет?
К каким серьезным багам будет приводить? Поясните.

Я же специально выше привел конкретный пример. В данном случае произойдет неправильное определение пермишена пользователя, т.е. сможет залогиниться тот, кто на это не имеет право.
Да и вообще примеров можно много привести. Любой кейс когда от существования объекта зависит логика. Например, могут удаляться связанные с этим объектом сущности
Ну не сможет. И что? Ответьте на вопрос — и что?! Это будет баг? И какие в ЭТОМ проблемы? Пользователь обратиться в поддержку и «глупого» админа пожурят, а роуты поправят. Проблема то где?
Вы уперлись в свою тантру и не хотите понять простого — вы не контролируете вообще ответ, который получите. Вообще. Вам кто угодно может ответить что угодно. Это суть HTTP. Это куча серверов между вашим фронтом и бэком. Админ ли у вас глупый или еще кто-то, какой-то вы там код свой придумаете или другой используете это ничего не поменяет. Только усложнит понимание вашей системы теми, кто будет в ней разбираться. И все.
Повторюсь еще раз, хотите консистентность это — RPC. Но вы автоматом теряете все профиты от HTTP.
Вы уперлись в свою тантру и не хотите понять простого — вы не контролируете вообще ответ, который получите. Вообще.

Ну так задача-то была контролировать. Если контроля нет — значит, задача не решена.

Да не было ее. В том то и дело. Попробуйте представить ситуацию, что вы не вольны управлять своим сервером. Т.е. вот он будет отдавать 404 и все тут. И попробуйте проработать свою стратегию работы в этом случае. Я уверен, что у вас выйдет сделать так, чтобы этого вам было достаточно.
Ну так ответ-то уже был выше. Отдавать ошибку бизнес-логики с кодом 200, а любой ответ 404 рассматривать как ошибку транспорта или конфигурации.
Ещё раз, транспорт легко отдаёт 200 с вообще левыми данными.
Но не с данными требуемого нужного формата, иначе это уже не просто транспорт, а злоумышленник mitm.
Ну не сможет. И что? Ответьте на вопрос — и что?

Вообще-то как раз сможет, хотя не должен. Кейсы могут быть разные от не критичных до очень критичных, которые могут выливаться в реальные финансовые/репутационные потери для бизнеса. Странно, что вы этого не понимаете.
Проблема то где?

Собственно в потенциальных багах, которые были бы невозможны в случае если 404 не будет являться ожидаемым респонсом.
Вы уперлись в свою тантру и не хотите понять простого — вы не контролируете вообще ответ, который получите.

Я не понял как это связано с обсуждаемое темой. Мы обсуждаем два варианта:
1. Когда мы можем отличить два состояния «ошибка роутинга» и «объект не существует»
2. Когда мы не можем отличить эти два состояния
2-ой вариант может приводить к багам, пример которых я привел, причем такие баги не всегда просто будет обнаружить. В 1-ом варианте эти баги исключены. К тому же если 404 не считается ожидаемым респонсом, то появление респонсов с таким статусом в логах приводит в срабатыванию алертов и более быстрой реакции на то, что, например, какой-то endpoint исчез
Я очень хорошо понимаю, что такое финансовые и репутационные потери. Так хорошо, что не каждый такой опыт имеет. Без бравады говорю. Именно этот опыт заставил меня относиться к REST как к дождю — это хоршо, когда он есть. Но не часто. И не сильный. И самое главное, я не могу на него повлиять. НО! Я могу взять зонтик или не выходить из дома.
1. Когда мы можем отличить два состояния «ошибка роутинга» и «объект не существует

Вам не нужно отличать эти две ошибки. В этом нет смысла. В любом случае вы не получите объект. Если уж сильно, сильно, сильно хочится, в респонсе 404 отдавать — Точно, объекта нет. Отвечаю.
2-ой вариант может приводить к багам, пример которых я привел,

Баги это или нет, но они нарушают работу системы как любой другой. И все, что вы можете сделать — зафиксировать наличие баги. Диагностика это вопрос не пользователя и не софта, а специалистов. И для этого есть логи.
В 1-ом варианте эти баги исключены.

Как? Баг есть. Админ роут перепутал. У вас 404. Что делать будете?
К тому же если 404 не считается ожидаемым респонсом

Вообще не учитывается админами. Это крайне распространенный штатный ответ. Разве, что наложены правила на алерты по 404.
какой-то endpoint исчез

Об этом должны говорить интеграционные тесты. Регулярные. Мониторинг. Но точно не уровень прилоежния. Все, что приложение может сказать пользователю — упс… у нас проблема. Обратитесь в сапорт.
Вам не нужно отличать эти две ошибки.

Нужно. В одном случае сервис спокойно упадет с 500кой (ну или как-то обработает ошибку, зная что это нештатная ситуация), а в другом будет выполнена бизнес-логика для случая когда объекта не существует.
Как? Баг есть. Админ роут перепутал. У вас 404. Что делать будете?

500тить, например. Это частичная неработоспособность системы. Плюс к этому на 500ки последует очень быстрая реакция. А в том что предлагаете вы из-за инфраструктурной проблемы каскадно начнет неправильно вести себя бизнес-логика. Получив 500ку я сразу по логам могу установить, что ее причиной было 404 от другого сервиса. А в вашем кейсе сломается логика, но никаких признаков что что-то идет не так не будет
Вообще не учитывается админами. Это крайне распространенный штатный ответ. Разве, что наложены правила на алерты по 404.

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

Роут может сломаться в любой момент, уже после прогона интеграционных тестов. А вот с мониторингом опять та же самая проблема, что мы не знаем в каких кейсах 404 это ожидаемое поведение, а в каких-нет.
500тить, например. Это частичная неработоспособность системы.

Это как? Роут перепутан… ничего до бэка не дошло. Просто 404. Что в этом случае?
Там где 404 не используют как нормальный респонс, конечно, накладывают такие правила для алертинга

Не в коем разе. Это плохая практика. Ибо вашу поддержку могут просто затроллить. Она сума сойдет разгребая запросы.
Роут может сломаться в любой момент, уже после прогона интеграционных тестов.

Может. Но это не значит, что он будет сломан постянно. Через установленный промежуток времени, мониторинг покажет ошибку. Она будет исправлена. Пользователи продолжат работу.
404 мониторингами не отрабатывается. Только для конкретных роутов, где скажем, на любой запрос, должен даваться ответ. Да думаю и там не будет. Обрабатываются 5хх ошибки.
Вообще 4хх не должно обрабатывать мониторингом. Только, повторюсь, в виде исключений.
Это как? Роут перепутан… ничего до бэка не дошло. Просто 404. Что в этом случае?

500тить будет клиент этого endpoint'а, получивший 404. Это нештатная ситуация, в которой клиент не может продолжить работать не получив эти данные.
Не в коем разе. Это плохая практика. Ибо вашу поддержку могут просто затроллить. Она сума сойдет разгребая запросы.

Вы сейчас имеете в виду запросы, которые приходят снаружи (браузер и т.д.)? Я же имел в виду в первую очередь взаимодействие между внутренними сервисами, где никто никого троллить не станет
Может. Но это не значит, что он будет сломан постянно. Через установленный промежуток времени, мониторинг покажет ошибку.

В таком случае мониторинг будет носить вероятностный характер. Т.е. нужны еще какие-то сложные правила, что от определенного endpoint'а должен быть какой-то процент не-404 ответов
500тить будет клиент этого endpoint'а, получивший 404.

Это я вообще не понял… какой клиент endpoint? Но даже если это откинуть, то вы просто преборазуете 404 в 500. Зачем-то… хотя суть ошибок разная. И главное, приравнивает (sic!) 404 к 500. Что мешает это сразу воспринимать как то, что вы хотите?
Я же имел в виду в первую очередь взаимодействие между внутренними сервисами, где никто никого троллить не станет

Хух… да я бы про это и слова не сказал. Тут можно делать что хочешь. Это контролируемый периметр. И, я это не считаю полноценным REST. По субъективным причинам.
В таком случае мониторинг будет носить вероятностный характер. Т.е. нужны еще какие-то сложные правила, что от определенного endpoint'а должен быть какой-то процент не-404 ответов

Да не нужно :) Просто не нужно это контролить. НО!!! Если речь идет о внутренних сервисах и клиентах, то да, 404 вполне резонно стоит контролировать. Тогда в этом есть смысл.
Это я вообще не понял… какой клиент endpoint?

en.wikipedia.org/wiki/Web_API#Endpoints
Если речь идет о внутренних сервисах и клиентах, то да, 404 вполне резонно стоит контролировать. Тогда в этом есть смысл.

Наконец-то мы поняли друг друга
то вы просто преборазуете 404 в 500. Зачем-то… хотя суть ошибок разная. И главное, приравнивает (sic!) 404 к 500

Ну как раз приравнивание ошибок происходит в вашем случае. Недоступность какого-то апи приравнивается к нормальному ответу. Это равносильно приравниванию пустого ответа от субд к отсутствию коннекта к этой субд
Все, я по кругу не люблю ходить. Когда будете создавать внешний сервис, когда дойдете до того, о чем я вам пишу, плз, если не сложно черканите, если я окажусь не прав ;)
Когда будете создавать внешний сервис, когда дойдете до того, о чем я вам пишу, плз, если не сложно черканите, если я окажусь не прав ;)

Это аргумент в стиле вы тут все неопытные юнцы, один я знаю как правильно делать? Или мне показалось?
Это факт того, что я могу быть уверенным в том, что я говорю, и даю вам возможность в этом удостовериться. А как это воспринимать, это вопрос вашего профессионального уровня. Я же могу, если у вас возникнут какие-то вопросы, что-то пояснить. Дополнительно.

Один из моих проектов в профиле.
я могу быть уверенным в том, что я говорю

уверенность никак не говорит о вашей правоте или неправоте. У кого-то может уверенность в противоположных вещах.
Один из моих проектов в профиле.

К слову, у вас в профиле никаких проектов нет. По крайней мере, для меня они не видны

Вы уверенность с самоуверенностью путаете. Слова похожи, но суть у них совсем разная ;)

www.cryptonit.net в профиле. Надеюсь, я ничего не нарушаю.
И еще раз, вам не нужно :) Все логика на существование элемента может только подсказывать валидации ибо при создании последнее слово все равно скажет база, смогла ли она создать или нет. (из-за конкуренции)
Все логика на существование элемента может только подсказывать валидации

Можете развернуть мысль. Я не очень понял что тут имеется в виду.
ибо при создании последнее слово все равно скажет база, смогла ли она создать или нет.

При чем тут создание, если речь шла о получении объекта? И при чем здесь база?
=Что значит плохая бизнес-логика? Что вы будете делать, если в бизнес-логике предусмотренны разные сценарии в зависимости от того существует объект или нет?= Использовать 410, как вариант, не?
Ну насчет использования именно 410 я не уверен. Но в любом случае это лучше 404 и позволит эти два состояния отличать. Если конечно есть гарантия, что никто другой между клиентом и сервером не может вернуть такой же статус
Уже лучше, но не всегда возможно. У 410 семантика «нет и никогда больше не будет», что неприменимо при простом отсутствии в базе и грозит кешированием отрицательного результата.
Кеша боятся — в Рест не ходить. По мне кешировать нельзя ничего при обмене данными без особых причин. Но вообще разумное возражение.
GET /api/banned-users/15/
И на основании ответа решает разрешить ли пользователю логин или нет


Не очень удачный пример. В этом случае надо вернуть пустую коллекцию или null, а не опираться на 404. Но вообще то говоря, рестрикшены не строятся по принципу разрешено все, что не запрещено, когда неизвестно, что именно запрещено.
Не очень удачный пример. В этом случае надо вернуть пустую коллекцию или null

Ну так я как раз об этом и писал, что в этом кейсе опираться только на статус 404 довольно опасно.
Золотое правило — вообще на него не опираться, и не будет проблем. Я не читал диссертацию, но никогда не использую 404 Not Found в качестве «Нет энтити». Это тот самый случай когда нужен и полезен 200 ОК и body — null. Если все палки ломаются вокруг этого, непонятно почему.
Золотое правило — вообще на него не опираться, и не будет проблем.

согласен
Если все палки ломаются вокруг этого, непонятно почему.

Вот и мне не понятно
Потому что нас волнует не наличие объект по заданному url, а наличие нужной записи в базе.
А с каких пор REST отвечает за наличие записей в БД? На ваш запрос может ответь вообще статика. И вернуть вам тоже самое что из БД. Или кэш.
С тех пор как на основе REST стали строить API.
Ну так как насчет ответа из кэша? Или статикой на ваш REST API?

Что вы понимаете под "татикой на ваш REST API"? Вот есть сервер приложений, он отвечает на запросы к API. Откуда возьмётся статика?

Очень простой факт, что любой высоконагруженный проект в итоге, приходит к тому, что часть REST обрабатывается самим web-server. Например он кэширует запросы к бэку и и скалдывает к себе, а затем, если кэш актуальный, отдает статику. И к БД не происходит обращений. Также микросервисы могут интервально генерировать статику из БД, а сам REST будет обрабатывать webserver. И что вы предполагаете тут отдавать?

Дело в том, что вы ограничиваетесь простейшими кейсами. И находите в них проблемы. Хотя их нет. Возьмите и помониторьте серьезные сайты на предмет работы REST. Сделайте выводы оттуда, а не из дебатов на хабре.
Если сделать то, что вы написали, как полагается, то статика будет отражать содержимое БД. А значит, исходя из результатов запроса всё еще можно будет судить о наличии объекта в БД.

А если сделать абы как, то, собственно, и всплывут те самые проблемы о которых и писали выше, когда ответ сервера ничего не означает, а ошибка бизнес-логики неотличима от транспортной.
Я пытаюсь вам донести, что REST в любой момент масштабируется. В этом его профиты. И в инфраструктуру вставляются новые сущности. Хотя все остальные даже не замечают этого. Это очень и очень круто.
И делать выводы о том, что чего-то нет в БД неверно. Нужно именно судить о том, что по этому урлу нет объекта. А где его нет… в кэше, в БД или еще где-то это вопрос вторичный. Вы получите 404. И вместо него просто не нужно ничего придумывать. Достаточно это принять и с этим работать.
Если хотите удостовериться в том, что ответ от бэка, то вводится новая сущность в загловки — fingerprint. По которой можно заключить о том, кто эмитировал этот ответ. Но чаще всего, это вредно отдавать фронту. И эта фича используется во внутренней инфраструктуре для идентификации в логах.
Но что делать, если задача в том и заключалась, чтобы определить есть ли что-то в БД?
Так :))) Тоже пошли по кругу. REST не БД, даже если ответ берется из БД. Это лишь частный случай реализации в определенный интервал времени. Давайте закончим, т.к. я вижу желание во что бы то не стало остаться при своем мнении. Я «биться» за «правду» внутри вас не горю желанием. Мне достаточно, что я точно знаю как это работает и почему. Это доказывается моими проектами. Один из них можете посмотреть в профиле.
REST не БД, даже если ответ берется из БД

Да собственно не важно БД или не БД. У нас есть ресурс с определенным URI и мы хотим проверить существование этого ресурса. Если мы получаем ложноотрицательный ответ (в случае когда 404 вернулся из-за недоступности сервиса) о существовании этого ресурса, то это неконсистентное состояние системы. В каких-то случаях такая неконсистентность допустима, в каких-то — нет
в случае когда 404 вернулся из-за недоступности сервиса

Недоступность сервиса — 503.
Я выше уже приводил конфигурацию, при которой обращение к остановленному сервису приведет к коду 404.
Не приведет. Это ошибка в инфраструктуре, точнее тотальные косяки в инфраструктуре и полный бардак в ней же могут привести к 404 при недоступности сервиса. Т.е. мы создаем себе трудности и героически их преодолеваем…
Разумеется, это ошибка в инфраструктуре. Но ошибка легко допускаемая и способная долгое время оставаться незамеченной.
Нелегко. Преобразовать 503 в 404… это нужно ОЧЕНЬ сильно постараться. ОЧЕНЬ. Админы и DevOps поправьте меня плз ;)

Я же приводил пример как это сделать. Ничего сложного, достаточно повесить под виндой статический сайт и его api на один порт. И ошибка будет проявляться только при отключенном api, но включенном сайте — то есть, как правило, в короткие промежутки рестарта службы.

Да что ж такое :))) Ну «не может быть» такого примера, понимаете? Это нужно ПОСТАРАТЬСЯ так сделать. Вы знаете как конфигурируется nginx для работы с бэком? Думаю нет, отсюда ВАША проблема. Он может либо проксировать на какой-то другой сервер, либо отдавать по правилам конфигурации. И в конфигурации ЧЕТКО приписываются роуты по которым будет жить бэк. И если там бэк не отвечает… это 503 или 502, не помню точно. Но уж точно не 404. Понимаете?
А если он проксирует, то другой сервер живет по той же системе. И тоже отдаст 5хх.
А уж если вы запроксируете напрямую в какой-то самопальный бэк… то… отгадайте, что ответит nginx если по этому порту никто не ответит?
Ну почему, я должен вам доносить очевидные вещи? Я уже и так вам «намекал», и так… теперь мне вменят переход на личсноти и т.п. :)))
Ну не может быть такого примера, понимаете?

навскидку:
  • Service Discovery стал вести не в тот контейнер
  • Ошибка конфигурации API Gateway
  • В коде сервиса сделали ошибку, что привело к изменению (или вообще удалению) url'а, и соответсвенно запрос на него всегда возвращает 404
  • Ошибка в роутах с regexp'ами типа user/[0-9]{2})/ user/42/ работает нормально user/666/ всегда возвращает 404
Т.е. с nginx тема не прокатила, теперь будем как-то по другому искать варики… возмите плз и сами найдите ответы почему эти сценарии надуманы. Правда — устал. Извините.
Т.е. с nginx тема не прокатила

Я вообще ничего про nginx не писал.
возмите плз и сами найдите ответы почему эти сценарии надуманы

Понятно. Все ваши аргументы против приведенных доводов сводятся к безапелляционным утверждениям в стиле
Ваш это не нужно
и
такого не бывает
.
Yep. Так и отвечаю. Уже 30 раз. Ровно так.
А вы так:
конфигурации API

и
Все ваши аргументы против


Так и общаемся…
Во-первых, вы пропустили вторую часть, которая про IIS и HTTP.SYS

Во-вторых, в том же nginx можно попросту забыть прописать location к api, или опечататься и сделать location для какого-нибудь apo. Если при этом для всего сайта целиком указана директива root — то результатом как раз и станет 404 в ответ на любой запрос к api.
Ответ сервера будет всегда релевантен событию. Более подробно можно почитать в мануалах по его конфигурированию. И IIS и nginx и apache.
Недоступность сервиса — 503.

Ну не надо передергивать. Вы прекрасно поняли что я имел в виду: например, сломали роутинг. По существу можете что-нибудь ответить? Что делать с неконсистентностью в случае когда она неприемлема?
Я вам это уже не единожды говорил — RPC. Причем именно он а не очередные велики. Т.е. с манифестом методов, параметров и биндом методов на uri.
Если отказаться от идеи использовать 404 как нормальный ответ от api это же решит проблему, которую мы обсуждаем?
Ну нет же. Прочитайте пожалуйста мою статью habr.com/ru/post/440900 в части «Коды ответа http в REST» там я популярно изложил все стадии «принятие» REST. Ну я же старался…
Прочитайте пожалуйста мою статью habr.com/ru/post/440900 в части «Коды ответа http в REST» там я популярно изложил все стадии «принятие» REST.

Прочитал. 404 упоминается ровно один раз:
Т.е. если не найден объект по запросу, это 404

Утверждение без какой-либо аргументации.
Если говорить про статью, я согласен, например, с доводами про использование http 500 и что вообще хорошо бы уже по статусу отличать состояние, когда все прошло успешно (2xx) от неуспешного (>=400, что с этим дальше делать клиенту уже другой вопрос). Но у меня есть претензия конкретно к использованию 404.
Так просто экстраполируйте это на 404. Не вижу разницы. Что ж мне для каждого кода статью делать?

Дабы прервать этот срач, предлагаю со стороны приложения добавлять какой-то заголовок по типу X-Application: true. Тогда можно проверить что ответ именно от приложения. Если только всякие прокси не урежут заголовок

Ну вот мы, ожидаемо, и пришли к тому, что одних http-статусов не достаточно и нужно отправлять дополнительные данные в body/headers и в клиенте опираться на них

А еще лучше какой-то хеш подпись, тогда можно отфильтровать еще и подделки

Чаще всего проблема в том, что люди не умеют вчитываться, т.е. читают но не видят. И этот тред прекрасное тому подтверждение. Он начился с того, что сам автор расценил мой пост как хайперский по отношению к статье, а он как раз, напротив, развивает его мысль. Теперь заканчивается тоже эпично. Буквально 2 поста до этого я пишу
Если хотите удостовериться в том, что ответ от бэка, то вводится новая сущность в загловки — fingerprint. По которой можно заключить о том, кто эмитировал этот ответ. Но чаще всего, это вредно отдавать фронту. И эта фича используется во внутренней инфраструктуре для идентификации в логах.


И тут бац
Дабы прервать этот срач, предлагаю со стороны приложения добавлять какой-то заголовок по типу X-Application: true.

потом бац
А еще лучше какой-то хеш подпись, тогда можно отфильтровать еще и подделки


Вопрос… с очевидным ответом — смысл тут распинаться?

А если админ ошибётся, и вы будете получать сутки 204 ответ?
Что за чушь вы несёте?! Пойти и сломать ваш сервер так, чтобы он возвращал чепуху — ерунда для админа. Но есть, короче, метод. На крутых REST проектах админам резиночкой мудики перетягивают, и они перестают генерировать нестандартные ошибки.


З.Ы. если админ ошибётся, вы будете, скорее-всего, получать 502, 503 или Timeout Error (забыл его код). Если ваш админ так не умеет — срочно бегите за резиночкой!

Слой транспорта может швыряться самыми разными ошибками, не только 404. Тут вам и 408, и 451, и 502/503, и что угодно. Чего он не может — так это слать куки и CSRF токены. Так что смотреть надо на них.

404 — это отсутствие ресурса. А ещё есть целый пласт 5xx ошибок и 4xx состояний.


  • Not found objects on search — это 200 код сервера. /api/search?text=substr должно вернуть пустой список при отсутствии результатов и 404 при недоступности /api/search
  • /api/path/video/1234 — это конкретный запрос ресурса — ролика с идентификатором. Если отсутствует любой узел, включая 1234, возвращается 404.

И не забывайте, что есть Timeout error, например, Bad Gateway, Service Unavailable. Почему вы думаете, что при проблеме доступа к эндпоинту обязательно будет возвращаться 404 код? 404 код возвращает роутер, проверяющий существование ресурса.

/api/path/video/1234 — это конкретный запрос ресурса — ролика с идентификатором. Если отсутствует любой узел, включая 1234, возвращается 404.
Как вы отличите ситуацию «видео с таким номером нет» и ситуацию «у нас еще приложение не до конца задеплоилось, так что роутинг не работает и веб-сервер отвечает стандартным 404»?
Как вы отличите ситуацию «видео с таким номером нет» и ситуацию «у нас еще приложение не до конца задеплоилось

503 service unavailable
Ставится на деплое и не сношается моск.

Такое api называется JSON-RPC. Не вижу проблем сделать к нему клиента, если не забывать смотреть на тело ответа (а если забывать — не понимаю зачем вообще нужен клиент и api).

Вы говорите как правильно, но иногда приходится делать не правильно, а совместимо. Я вам приведу живой привер.

Абсолютно реальный, не надуманный кейс, с которым лично я сталкивался три раза: два раза на мобильных клиентах германии, находящихся в роуминге (один из них Т-мобайл, второй уже не помню), один раз — на итальнском мобильном операторе (вне роуминга, в родной сети).

Выглядит следующим образом — все, что попадает на мобильный телефон — проходит через прокси мобильного оператора. Прокси оператора, видя стандартные коды ошибок (400, 401, 403, 404 (!), 500) режет ответ вашего сервера. Он отрезает весь ответ после заголовков (с целью экономии трафика?). Поэтому любые детали об ошибке, которые вы передаете в теле ответа — просто теряются.

А вот 200й ответ не режется никогда (конечно, субьективное мнение, не более). Пережимается (удаляются переносы строк, не значащие символы) — видел. Но это не мешает его правильно интерпретировать клиенту.

Поэтому в случае, если вам нужно быть максимально совместимым — я бы как раз рекомендовал обратное — отдавать ошибки столь ненавистным вам способом.
https спасёт отца русской демократии от вмешательства опсосов и прочих барабашек.
подобный прокси это хрестоматийный пример man-in-the-middle: вы можете гарантировать, что они не подменят сертификат и не сделают то же самое?
Для подмены сертификата провайдером нужно решение на государственном уровне, и всё равно есть способы защиты.
нужно разрешение или нет на государственном уровне — вообще-то зависит от законодательства той строны, где сейчас находится, к примеру, в роуминге ваш мобильный клиент.

а при этом решение с ответами 200й будет работать — в любых условиях. https/https, сниферы/прокси, реальные сертификаты/подменные.

просто будет работать. всегда и везде.
Да не будет оно работать всегда и везде. 200 ОК с сообщением об ошибке моментально закешируется и всё, алес капут.
плохой довод, играет и против вас, и против меня. если кеширование на прокси настроенно настолько не правильно, что кеширует разные по длине/хидерам 200е ответы — оно точно так же, может кеширвоать и не 200е коды.

или же — кешировать ваши правильные данные (без ошибок) для вашего варианта — вне зависимсоти от того, как вы кодируете на уровне протокола сами ошибки.

плюс — приведу ваш же довод — ssl.

ну а в варианте — прокси, с подменой сертификатов. да и не правильно настроенным кешированием — апи просто не будут корректно работать.
Да при чём тут прокси, сам браузер 200 ответы и закеширует.
Повлиять на политику кеширования браузерами вы не можете, придётся плясать по их правилам. А для них 2хх — это коды годных результатов.
почему это вдруг наш клиент — браузер?

вы, пардон, описываете принципы построения REST JSON API, а не «особенности построения REST JSON API для браузеров».

там может быть и мобильный клиент, и интернет вещей как клиент — да кто угодно.

да и с кешированием 200х ответов по API браузером вы, мягко говоря — лукавите.
Повлиять на политику кеширования браузерами вы не можете

А Cache-Control на что?

Если ошибка выброшена промежуточными слоями (прокси, балансировщиками, самим браузером), то cache-control там не будет, или будет такой что лучше бы его не было.

А разве речь тут шла об ошибках промежуточных слоёв? Мне почему-то казалось что тут обсуждается с каким кодом сообщать об ошибке бизнес-логики.


И да, ошибки промежуточных слоёв разве с кодом 200 идут?

Специально зашёл на ресурс имени роскомпозора — 451 там и не пахнет, всё 200 и пара 302 зачем-то.
А кто, собственно, мешает провайдеру в таком случае подменять ответ сервера даже со статусом 200? Только совесть.

По науке автор прав — не надо прогибаться, есть стандарт.
На практике, конечно, выйдет немного по-другому — если есть нужда работать через такой прокси в такой позе — будет работать, или у тебя, или у следующего разработчика.
Значит, сервер должен иметь lame duck mode специально для такого случая, который активируется или дополнительным хедером, или параметром, или протоколом, или просто по IP.

Чего совершенно нельзя делать, так это брать нестандартные решения и делать из стандартными — суть стандартов в том, что они более-менее универсальны.

С тем же успехом может прийти какой-нибудь камрад с монгольского прокси и выдвинуть несовместимые требования — мол, у нас HTTP 200 считаются трафиком, а остальные нет, давайте 204 вместо 200.
Вы когда-нибудь пытались сделать клиента к апи, которое на всё подряд кидает 200 ОК?

Легко. HTTP — это всего лишь транспорт, и 200 обозначает что ответ получен от приложения, а не кого-то ещё, следовательно, можно разбирать тело, а уже в нём всё написано.

Если это не 200, значит, проблема с сервером, прокси или что там ещё по пути к приложению, и разбирать тело смысла не имеет (так как оно не от приложения). Можно возвращать 4xx для того что можно валидировать до приложения (формат, авторизацию и т.п.), но не более того — сам запрос (правильный json) должен обрабатываться только приложением, и только оно может на него ответить.

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

К примеру, Cloudflare API использует именно этот метод — и это весьма удобно, там вообще нет ответов кроме 200 и 301 (все 4xx это проблемы с запросами ещё до того как они попадают в приложение).

Натягивание кодов ошибок HTTP на возможные ситуации с приложением (которых может быть на порядок больше чем в HTTP, не говоря уже о том что ошибок может быть больше одной и разного типа, и все их нужно обработать) — плохая практика.

При обработке сложных запросов также возникает необходимость возвращать более чем одну ошибку (особенно если запрос обрабатывает более одного объекта), причём разного рода — и все их нужно обработать. Простой пример — пользователь отправил форму, в ней с десяток полей, некоторые с ошибками — будет весьма логично вернуть список всех ошибочных полей за раз, а не останавливаться на первом и возвращать их по мере того как он их исправляет, при этом ошибки могут быть разными («неверный формат», «недопустимое значение» etc), это всё не влезает в линейку 4xx.

Ещё более жесткий случай если мы создаем несколько объектов в одном запросе (batch processing), при этом допускается что не все они будут созданы (частичный успех) — тут 201 никак не поможет, а попытка создание объекта который уже есть (и может быть только в одном экземпляре) вообще никак не отображаема в HTTP — можно было бы использовать 409, но тогда это неотличимо от других конфликтов. В общем, много таких вещей, которые в HTTP не влезут при всём желании, без изобретения своих кодов.

Пример плохого дизайна — в PowerDNS API — на всё что сервер не понял он возвращает «422 Unprocessable Entity», а в теле — текстовое описание проблемы, которое совсем почти непарсабельно (да и может измениться в любой момент, ибо даже не документировано).

Но разумеется, если у вас приложение само является endpoint, перед ним нет даже хиленького LB, а все возможные ошибки «влезают» в 4xx/5xx — тогда да, в самый раз. Увы, в реальности такое бывает редко.
Batch processing в http есть, не скажу что прям просто реализуется, но есть.
Вопрос в том, что отказываясь от нормальной работы с HTTP, вы также отказываетесь от большей части инфраструктуры (балансировщики, кэши, прокси, мониторинг, etc). На всё можно свои велосипеды наколхозить, только зачем? Тогда уж лучше взять какой-нибудь стандартный RPC типа SOAP, где есть своя инфраструктура.
Batch processing в HTTP нет, есть только pipelining, а это совсем не то же самое (хотя в ограниченных случаях и применимо). В HTTP вообще почти ничего нет — это просто транспорт, не более того. Да, получивший широкое распостранение и вне web, передающий уже давно не только HTML, обросший прокси, кэшами и LB, но всего лишь транспорт.

Честно говоря, я не вижу каким образом использование HTTP только как транспорта (как я описал) заставляет отказываться от инфраструктуры, и одновременно сильно упрощает как клиента, так и сервер, потому что весь цикл обработки примерно такой:
  // Сервер
  while (GetRequest()) {
    ProcessRequest()
    SendResponse()
  }
  // Клиент
  while (HaveJobs()) {
    SendRequest()
    ProcessResponse()
  }

и всё — код никак не зависит от транспорта, кроме Get/Send.

GET может кэшироваться как и обычно (если нужно и разрешено), остальное спокойно проходит через всё что угодно без потерь (при наличии «умного» прокси-кэша-LB тоже может ограниченно кэшироваться — даже PUT, PATCH, POST и DELETE), при этом клиент гарантированно знает что любой код отличный от 200 обозначает только одно — запрос не попал в приложение (что и требуется — в этом суть транспорта). Мониторинг тоже не страдает — просто может потребоваться добавить разбор тела (причём это стандартная возможность любого приличного мониторинга), но и это не всегда нужно — потому что (снова) — 200 означает «всё ок». Балансировщики — тоже в порядке, ибо если приложение отвечает 200 — значит оно доступно, для недоступности есть 5xx (или таймаут, или connection refused). Что ещё?

Я лично использую этот «велосипед» уже более 15 лет, за стеной прокси, LB и мониторинга, им очень активно пользуются несколько тысяч клиентов — никаких проблем, всё работает как часы (хотя в начале это был не JSON а XML, не SOAP, свой).

Да и пример с Cloudflare я не случайно привел — они на HTTP и всей инфраструктуре целую армию собак съели, но их собственное API использует HTTP только как транспорт, и это реально удобно, но если они захотят, то почти без усилий могут его сделать доступным хоть по почте (SMTP).

Вот только зачем это всё для отображения камментов каким-нибудь vue.js?
Велосипеды со всякими {error: «message»,«result»:...} невозможно нормально тестировать и отлаживать

Кто привык к этому, добро пожаловать в GraphQL, там нет заморочек с кодами возврата, адресами ресурсов (точка входа вообще одна). Все очень просто устроено.
418 I'm a Teapot

Существует только в первоапрельском RFC 2324, то есть не включен ни в один стандарт. И даже по вашей логике его отличия от стандартного 400 Bad Request довольно неопределённые.
UFO just landed and posted this here
Именно, что 418 первоапрельский RFC, и поэтому не будет выкинут ни одним промежуточным софтом.
В дев/staging окружении 418 это железобетонный баг клиента, можно прям автоматом баг заводить в трекере.
На проде 418 означает, что клиент у нас хакер, спамер, сканер или фаззер, и его можно спокойно отдавать fail2ban или аналогу.
418 первоапрельский RFC, и поэтому не будет выкинут ни одним промежуточным софтом
Не понял причинно-следственной связи: почему не будет?

RFC 2324 Status: INFORMATIONAL

Strict-реализация HTTP совершенно спокойно может отбрасывать коды вне стандарта.
Вы же не будете утверждать, что различный софт и железяки должны поддерживать вот это всё.
> Идемпотентный запрос, т.е. повторный DELETE с таким же адресом не приводит к ошибке 404.

Можете аргументировать?
Тут еще вопрос, как реализовывать идемпотентность: токеном или просто по URI.
Но вообще, причина в ненужной ошибке, которая испугает пользователя, если произошел разрыв соединения в каком-нибудь тоннеле.
Идемпотентность в контексте http не означает что response status должен быть одинаковый, а говорит только о том, что при повторных запросах не должно появлять дополнительных сайд-эффектов на стороне сервера.
> Идемпотентный запрос, т.е. повторный DELETE с таким же адресом не приводит к ошибке 404.

Можете аргументировать?

Вы отправляете DELETE запрос на ресурс с ID 100.
Ресурс удалён? Удалён. Возвращаете информацию о том то удаление прошло успешно, вот и всё )
Можно ещё запариться с ключами идемпотентности. Хорошая статья была совсем недавно — habr.com/ru/company/yandex/blog/442762

Всё, описанное здесь, конечно хорошо и здорово. Наверное, стоит прислушаться к полезным пунктам этого поста, но не нужно путать теплое с мягким.


REST API это всего лишь два слова, не несущие никаких четких стандартов. Никто не обязывает использовать HTTP или не использовать "велосипеды со всякими {error: "message","result":...}".


Соответственно, все пункты, касаемые того, что должны делать сервер и клиент (заголовки Accept, тип text/plain при ошибке, использование множества кода ошибок вместо 200/400/500, в крайнем случае — 404, причем зачастую люди трактуют их неверно, привет коду 418), это не стандарт, а пожелание автора, пусть хорошо понятное и в целом для многих справедливое. Нужно помнить об этом.

Стандарт HTTP это стандарт. Его несоблюдение вредно для кармы и ведёт к постоянным проблемам с безопасностью, кэшированием и прочими «закидонами» браузеров, которые совсем не закидоны, а просто следование стандарту.

Непонятно, каким образом это относится к REST API. Это относится к любому неправильно спроектированному API, нет разве?

Велосипеды со всякими {error: «message»,«result»:...} невозможно нормально тестировать и отлаживать

Не могли бы раскрыть свою мысль?

Поддержка большим количеством готовых клиентских библиотек на все случаи жизни. Те, кто будет вашим api пользоваться, скажут большое человеческое спасибо.

Тоже интересно узнать подробности, о чём конкретно идёт речь?

Поддержка автоматизированного интеграционного тестирования. Когда сервер на любые запросы отдаёт 200 ОК — ну, это такое себе развлечение.

Ну так надо смотреть тело, разве нет?

Вообще, натягивание статусов протокола на приложение, как по мне, не самое лучше решение.
Если я отправляю запрос на получение сущности, а возвращается 404, что это? Страница не найдена вообще или сущность не найдена? Как это различать?

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

Т.е. в целом, я не против REST API, но это всего лишь соглашение, не всегда удобное, не стоит его навязывать всем.
Велосипеды со всякими {error: «message»,«result»:...} невозможно нормально тестировать и отлаживать

Почему вы считаете это велосипедом? Microsoft API

Если клиенту нужно отобразить ошибку? Даже тривиально — результат валидации?

Оборачивать результат списка ресурсов (GET /entities) необходимо для закрытия уязвимости JS Array, которая может привести к утечке данных.
Побочным бонусом от этого оборачивания становится возможность докинуть информацию о пагинации не в заголовки.
А что-за уязвимость, ведущая к утечке памяти? Не наследие ли это всяких IE6, Netscape?
Про побочный бонус — категорически согласен.
Не памяти, а данных. Когда сторонний клиент (например, расширение браузера) может получить доступ к тому, что ваш API передал через свой контракт ответа.
Уязвимость 10+ летней давности с перезаписыванием Array
Побочным бонусом от этого оборачивания становится возможность докинуть информацию о пагинации не в заголовки


С этим соглашусь. Добавил в статью.
Если вы используете защиту от CSRF (а лучше бы вам её использовать), то удобнее передавать CSRF-токен в отдельном заголовке (типа X-CSRF-Token) для всех запросов, а не внедрять вручную в каждый запрос. Хранить CSRF токен в куках плохо по той причине, что куки можно украсть, в чём собственно и состоит суть CSRF атаки.


Это не верно.

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

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

В-третьих, никто не использует кукисы с CSRF-токенами без хеадеров. В этом нет никакого смысла. Поскольку кукисы проставляются и отправляются браузером автоматически, то они не дают сами по себе никакой защиты. Сайт злоумышленника, попытавшись отправить запрос от имени пользователя, успешно это сделает, если кроме кукисов ничего нет. Поскольку браузер проставит все кукисы сам.

Вся суть защиты состоит в том, что клиент отправляет одновременно токен и в хеадере, и в кукисах. И этот токен должен совпадать.

Уточнение: только не в хеадере, а в теле запроса. Если же отправлять в заголовках HTTP — то кукисы уже не нужны, поскольку сам факт наличия постороннего заголовка означает, что этот запрос сформирован тем, кому разрешено добавлять заголовки в запросы.

> Придумать реальный use-case, когда реакция клиента будет различаться в зависимости от 404 или 410, довольно сложно.

Самый простой пример — проверка никнеймов или страниц, связанных с ними. И если мы заходим на несуществующий никнейм — мы видим 404 и кнопку «Занять никнейм», а если кто-то уже когда-то занял его, а затем удалил свою страницу (прямо как в ВК), то кнопка «Занять никнейм» уже не появляется.
а чем RPC плох? по мне так использование http кодов и методов нафиг не нужно ни браузеру ни коду, это выглядит как хаки, пытаться впихнуть в стандарт то что там не должно быть, с урлами такая же хрень, ведь нужно только название метода которое должно быть понятно и всё можно через пост посылать, может конечно я где-то не прав, но ведь по идее нужно удалённое выполнение функции которая чтото вернёт или не вернёт ответ, а хттп всеголишь способ коммуникации
> использование http кодов и методов нафиг не нужно ни браузеру ни коду
Браузеры обрабатывают http-коды по-разному. Множество инструментов по-умолчанию настроены на стандарт и отвечают соответственно.

Коду тоже нужно. Когда вы используете самый стандартный `fetch API` в браузере, он учитывает коды и выдает TypeError в случае 4xx/5xx

Метод OPTIONS, тоже как часть стандарта, определяет возможности сервера и участвует в CORS.

P.S. Junior'ы, ключевое слово сообщения сверху — «по мне».
rest api правила придуманы не просто так, а для упрощения интеграции, это нужно когда нет или не хочется писать хорошую документацию, если мы включаем всякие автогенераторы документации и генераторы кода, то смысл в этом всём пропадает, становиться можно писать апи любой сложности и вообще не думать как оно по сетке посылается, как в общем никто и не думает при вызове метода сторонней библиотеки из кода, становиться не важно где код исполняется, на этой же машине в этом же процессе или где-то удалённо, это всеголишь ещё одна библиотека которой можно пользоваться, разве это не то что всем в конечном итоге нужно или будем топить за rest api чисто чтоб по феншую было?
А почему ошибка передается «без всякого JSON»?
Потому что ошибки будут отдаваться в том числе и на транспортном уровне безо всякого JSON.
И вас будет двухуровневый код обработки ошибок — сначала смотрим http статус, а затем пытаемся распарсить тело ответа. Вопрос — а что это даст? В чём смысл?
сначала смотрим http статус, а затем пытаемся распарсить тело ответа.

Да разные случаи бывают, например возьмем код:
408 Request Timeout
Сервер предположить, когда следующий запрос может быть обработан и переслать в теле эту информацию, чтобы не «дидосить» API или не заставлять пользователя ждать слишком долго.
Да и вообще коды 4xx в стандарте описываются так, что они могут отражать некоторую детализацию ошибок:

Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition. These status codes are applicable to any request method

В общем полезная статья, но я бы не стал слепо следовать ей во всех случаях.
* При создании (апдейте) объекта, не вижу ничего плохого чтобы вернуть этот самый созданный\обновленный объект чтобы сократить таким образом коммуникацию и избежать доп. нагрузки когда всегда следом прилетит GET на тот же объект
* Считаю что очень нужно и правильно при 4хх ошибках возвращать в JSON доп информацию по ошбке. Как то: код\константу ошибки. Сопровождающий текст. Возможно какую то информацию requestUUID и.т.д. Возвращать тело ошибки текстом когда вся остальная система работает с JSON — как минимум странно

Так же в статье деликатно обошли множество моментов, когда при формировании API сложно создать правильный URI с точки зрения операций над объектами (операции не являющиеся созданием или получением ентити и какие-то промежуточные операции).

При создании/обновлении объекта методом PUT ни ответа, ни последующего GET не требуется: ведь новое содержимое объекта должно соответствовать переданному с точностью до форматирования.


А вот в ответ на запрос PATCH должен возвращаться полученный объект, и об этом написано.

Это не всегда так. Если, допустим, сервер добавил какие-то поля при создании объекта (например, дата создания или автоматически сгенерированный uuid), то отдельный гет на каждый такой пост выглядит избыточным. Проще и дешевле возвращать объект в ответе целиком.

Конкретно в описанном варианте чистого REST-CRUD метод PUT должен использоваться только в том случае, когда объект передаётся на сервер целиком, а сервер не имеет права добавлять к нему никаких дополнительных значимых полей:


A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response. — RFC 7231, 4.3.4 PUT

Если передаётся лишь часть полей — надо использовать PATCH. Или перестать играть в REST и использовать обычный POST.


Как вариант, можно выделить субресурс с частью полей и делать PUT для него.

Я имел ввиду ответ на пост запрос. Про пут или патч речи не было)

Но я-то писал про PUT и PATCH…

Согласен, моя невнимательность) Прошу прощения

  1. Как отправлять файлы на сервер тут написано, а как скачивать через api — нет. Если следовать всем этим рекомендациям в лоб, то придётся, того и гляди, кодировать файлы в base64 и отправлять на клиент как строку json.


    Мне почему-то кажется, что для части api, работающей с файлами, допустимо использование любых Content-Type. И каждый файл нужно передавать под его "родным" Content-Type, а не как-то ещё.


  2. Неидемпотентность POST может оказаться проблемой. Решением может стать генерация id на стороне клиента и создание сущности методом PUT.


  3. Описание ошибки в text/plain не всегда хорошая идея. Например, если разные ошибки требуется обрабатывать по-разному, а кодов HTTP не хватает. Или если предполагается перевод сообщений об ошибках на стороне клиента.


Видел я и base64 в json:)
Но вообще статику отдают отдельным nginx веб-сервером, до кода api такие запросы даже не долетают.
Так это ж не статика. Это те самые данные, которые ранее были загружены на сервер через api.
Автор, то что вы описываете в статье называется Remote Procedure Call (RPC), а не REST.
У вас не происходит управления состоянием клиента со стороны сервера, вы просто предоставляете эндпоинты для вызова процедур. Вот даже возмущение Роя Филдинга по этому поводу, хотя вы видимо, о нем, даже не слышали. Уточню, Рой Филдинг — это человек который ввел понятие REST в своей диссертации в 2000 году.
И понятие это обозначает наложение некоторых ограничений на архитектуру системы:
1. Starting with the Null Style — клиенту не нужно знать про сервер абсолютно ничего кроме одной единственной точки входа, все дальнейшие возможности для переходов идут с сервера. В полноценных REST API, если взять например те REST API что возвращают HTML как гипертекст (см. HATEOAS — hypertext as the engine of application state), это будут теги и теги . У вас же просто кучка ендпойнтов которые клиент уже должен знать.

2. Client-server и Separation of Concerns
A proper
separation of functionality should simplify the server component in order to improve
scalability. This simplification usually takes the form of moving all of the user interface
functionality into the client component. The separation also allows the two types of
components to evolve independently, provided that the interface doesn’t change.

Ваш клиент и сервер могут бесконечно масштабироваться и изменяться(развиваться) независимо. Как, например, Google не нужно обновлять браузер Chrome который представляет собой клиент каждый раз когда обновляется какая-то страничка в интернете, все что требуется от клиента и сервера — обмениваться данными в том формате которые они оба понимают(см. Unified Interface), функциональность клиента так же может быть расширена не обязательным 7 пунктом (Code on demand)

3. Stateless. Отсутствие состояния соединения. Благо хотя бы до нарушения этого пунктика статья ещё не дошла.

4. Кэширование. В статье не упоминалось, но напомню что это один из 6 пунктиков который должен обязательно выполняться чтобы вы могли назвать своё API REST

5. Uniform Interface. То, что я частично описал в п.2… У вас клиент не должен знать что определенный эндпоинт вернет определенную структуру данных. Чтобы обеспечить масштабируемость и независимую разработку, устраняется любой Coupling между клиентом и сервером, и всё что умеет клиент — отображать стандартные форматы данных(как браузер отображает html, jpeg, etc.).
Чтобы получить единый интерфейс системы накладываются так же такие ограничения как:
— Идентификация ресурсов;
— Выполнение действий над ресурсами через представления;
В вашем же случае идет просто обмен заранее известными структурами данных(Привет RPC).

6. Многослойная система(не затрагивается в рамках этой статьи).

7. Code on Demand — возможность загрузки кода с сервера в виде апплетов или скриптов для расширения функциональности клиента — например научить понимать его новые форматы данных.

Вот эти вот принципы, перечисленные выше, являются принципами построения REST API, а не урлы красивенькие сделать поверх JSON RPC.
Вся ваша статья лишь о том как должен выглядеть http запрос и какие должны быть урлы, только вот «REST ignores the details of component implementation and protocol syntax to focus on the roles of components, the constraints upon their interaction»(с) Dissertation

И нет, это не плохо, и не хорошо, это просто разные архитектуры, стили написания API. REST он о том, как функционировал web без этих ваших громоздких SPA на JS, REST накладывает ограничения которые могут быть вам не нужны. Реализовать мобильный REST-клиент это по сути изобрести новый мобильный браузер. Возможно, правда, за основу брать не HTML.
Просто не нужно подменять понятия, да и ещё пытаться учить этому новичков.

На русском советую почитать хотя бы это — habr.com/ru/post/319984.
На английском — диссертация и roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

Если речь идёт о чём-то кроме гипертекста, а клиент является чем-то кроме браузера, то клиент в любом случае должен понимать схему данных, хотя бы минимально.


А если клиент работает без участия пользователя — то без строгой схемы данных ну никак не обойтись.

Если речь идёт о чём-то кроме гипертекста, а клиент является чем-то кроме браузера, то клиент в любом случае должен понимать схему данных, хотя бы минимально.

Без проблем, только REST-ом это не называйте. Я упомянул что реализовывать свой кастомный REST клиент вместо существующего(в виде браузера), весьма затратно.

В случае если ваш клиент описыват лишь стандартные типы данных, которые он умеет принимать, а все данные, и информация о том как их правильнее отобразить приходит с сервера, ничего про структуры знать не нужно.
Но в таком случае зачем вообще придуман термин REST? Для интерфейса «как в браузере» уже есть название — «браузер». И для протокола HTTP тоже есть название — HTTP.
Но в таком случае зачем вообще придуман термин REST? Для интерфейса «как в браузере» уже есть название — «браузер». И для протокола HTTP тоже есть название — HTTP.

REST был придуман 19 лет назад, и тогда он действительно был нужен, и успешно решал некоторые проблемы. А Рой Филдинг является одним из авторов спецификации HTTP, так что их схожесть, точнее то как он удобно ложиться на HTTP вовсе не случайное совпадение )
Взаимодействие клиентов и серверов в браузере действительно строилось и строится по REST архитектуре, то что это не особо укладывается в архитектуру модных нынче SPA, или не удовлетворяет потребности мобильных разаботчиков, решает проблемы которых их не интересуют не обозначает что нужно обобщать термин REST до уже существующего RPC. Ещё раз повторюсь, RPC — не плохо. RPC это другой стиль решающий другие проблемы, если он решает ваши проблемы, а он решает проблемы большинства, RPC — это хорошо.

Ну всё же REST он не о протоколе передачи данных, а о взаимодействии компонентов.

Вы сейчас занимаетесь тем же самым в чём обвиняете оппонентов: вольным расширением терминов. RPC — это, конечно же, хорошо — вот только всё что описано в обсуждаемой статье нормальным RPC не является.

RPC это весьма широкое понятие, в отличии от REST, так что мне интересно услышать чем описанное в статье не «Удаленный вызов процедур», речи о JSON-RPC, я, заметьте, не вёл
Диссертацию вы может и читали, но ничего в ней не поняли.
Допустим, у вас бложик. Есть три типа сущностей — записи, комментарии и юзеры. Это три разных ресурса, у которых должно быть три разных URI. Никто не предлагает свалить это всё в одну кучу с одной точкой входа. Клиент, собирающийся получить ресурс, должен знать URI этого ресурса. Это фундаментальная основа всего стиля REST.
Как оно там на сервере будет обрабатываться — одной точкой входа, которая ловит всё, или отдельным файлом на каждый эндпоинт — это дело сервера, знать о котором клиенту не обязательно.
Второй столп — полное единообразие на уровнях OSI от транспортного до прикладного. Описанное в статье как раз этому и соответствует. Неважно какой запрос, с одной стороны запихиваем данные в формате JSON, с другой их же и достаём, не задумываясь об их преобразованиях под капотом.
Никаким RPC здесь и не пахнет.
Выше прикладного уровня REST не лезет и не должен, это уже слои бизнес-логики. И да, специализированные клиенты должны немного знать о бизнес-логике, на то они и специализированные.
Второй столп — полное единообразие на уровнях OSI от транспортного до прикладного. Описанное в статье как раз этому и соответствует. Неважно какой запрос, с одной стороны запихиваем данные в формате JSON, с другой их же и достаём, не задумываясь об их преобразованиях под капотом.
Никаким RPC здесь и не пахнет.
Выше прикладного уровня REST не лезет и не должен

REST это то что описано в документации Роя Филдинга, а описано там 7 конкретных архитектурных ограничений, не нужно выдумывать что-то своё и коверкать понятия.

Есть три типа сущностей — записи, комментарии и юзеры. Это три разных ресурса, у которых должно быть три разных URI.

Это один подпунктик из 7 архитектурных ограничений. Если вы прочитаете мой комментарий то поймете что речь шла о том что клиент про эти URI для начала взаимодействия с вашим сервером знать не должен. Точно так же как мне чтобы читать блог Мартина Фаулера не нужно помнить URI каждой его статьи, так и клиенту для начала взаимодействия с вашем API не нужно знать ничего кроме одной единой точки входа.
Курите ограничение номер 4 «Единообразие интерфейса», подпункты «Идентификация ресурсов» и следующие два. Пока вы их не осилите, спорить с вами не о чем.
Я обновил комментарий, и уточнил там про идентификацию ресурсов. Ещё раз подчеркну — всё что я выше описал этому принциму никак не противоречит, и каждый ресурс должен иметь URI.
UFO just landed and posted this here
Видимо, все кто понял что статья ни о чём просто минуснули прошли мимо, что вобщем то видно по рейтингу статьи. А наш удел остаться тут заминусованными. Печально что на Хабр можно писать любые глупости, и если делать это достаточно убедительно, сотни новичков в поисках информации что такое REST будут натыкаться именно на эту статью…
Уж лучше на эту, чем на тот диссер. 20 лет назад ни JSON, ни даже AJAX ещё не было.
Уж лучше на эту, чем на тот диссер. 20 лет назад ни JSON, ни даже AJAX ещё не было.

Не делать REST API — хорошо. Никаких проблем.
Коверкать понятия — никода не хорошо.
Описанное в статье полностью соответствует всем принципам REST.
Делать кривое АПИ и изобретать велосипеды — плохо.
Описанное в статье полностью соответствует всем принципам REST.

Как это соответствует как минимум приниципу HATEOAS, если у вас в API не отдаёт гипертекст?
roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Делать кривое АПИ и изобретать велосипеды — плохо.

Да, плохо.
Как это соответствует как минимум приниципу HATEOAS

За 20 лет веб ушёл «немного» вперёд. Кроме того, здесь речь о JSON REST, а не HTML REST.
JSON REST, а не HTML REST.

Ссылочками на спецификации не поделитесь? А то пока что стойкое ощущение что определения вы выдумываете на ходу

А ещё — «REST ignores the details of component implementation and protocol syntax to focus on the roles of components, the constraints upon their interaction»
Наговорить глупостей, и тихонько кидать минусы на комментарии и в карму. Мне то без разницы, просто за Хабр обидно. Я ведь тоже когда-то думал что «Ну солидный ресурс же, на Хабре фигни не напишут»
UFO just landed and posted this here

В реальном мире большинство REST-сервисов не являются таковыми стопроцентно с академической точки зрения, и это нормально, так как они эффективно решают задачи, ради которых создавались. Такой подход можно назвать "Pragmatic REST". Более того, существует модель зрелости Ричардсона, в которой HATEOAS отмечен как то, к чему следует стремиться, но не то, что обязательно должно быть изначально, чтобы считаться REST (https://martinfowler.com/articles/richardsonMaturityModel.html). Так что в реальном мире выкрики в стиле "Или делайте 100% полностью как описано у Филдинга, или не называйте это REST!" считаю неуместными.

Спасибо. Много раз ловил бэкендеров с такими велосипедами, что волосы дыбом. Будет куда отправить просвещаться теперь
Потому что вам может прилететь ошибка в неизвестном формате, в том числе от транспортного слоя.
Но зачем при этом заявлять в запросе о том, что допустим любой формат сообщения об ошибке, в том числе всем транспортным слоям?
Не знаю, спросите у разработчиков браузеров в первую очередь. */* это они вставляют.

Очередной велосипед. Зачем? Есть стандарт OData.

Очередной стандарт MS, 5 версий за 3 года. Спасибо, не всем это интересно.
Это не стандарт MS, это стандарт от ru.wikipedia.org/wiki/OASIS

5 версий? Я знаю только 2. И то, последняя содержит не изменения, а дополнения. Да и вообще, от версии к версии стандарт не изменяется, а только дополняется.
Каждый раз, когда я вижу описание принципов REST API, мне хочется узнать: как организовать удаление нескольких объектов по одному действию пользователя? Без использования тела запроса.
RFC 7231 specifies that a DELETE request may include a body, but that a server may reject the request.

Из заголовка подумал что о нем и пойдёт речь. Оказалось нет, снова старые песни о главном.

Тот случай когда детище переросло своего создателя и живет отдельной от него жизнью. То чем является REST сейчас в общепринятом (насколько это возможно в отсутствии стандарта) представлении к исходной диссертации имеет касательное отношение.
Мне одному кажется что тут RFC в весьма вольном переводе?
Для знакомых с темой либо избыточно либо поверхностно, а для новичков не прояснилось ничего. Мне видится гораздо более перспективным описание языка декларации сервисов для любых категорий возможных читателей. Может быть я слишком пристрастен, конечно.
Суть REST гибкость, отраженная в нескольких строгих правилах. Которые наглухо проигнорированы в статье.

1. Что значит только UTF-8? Господин обдолбался пыхом? Что запросит клиент, то и будет, захочет US-ASCII — пожалуйста, или UCS-4 попросят, так держите на здоровье. И никакие «веселые» случаи тут не предусмотрены. Если ответ в json — он соответствует RFC 7159, все, шаг влево-вправо, расстрел несоответствие стандарту. Кричим «у нас легаси» и посыпаем голову пеплом. Дело обычное, никто не застрахован.

2. Где хранить CSRF-Token нигде не определено. И не просто так. Заявлять, что в куках нельзя никак хранить, странно. Если утащили куки, то компрометация CSRF — это меньшая из проблем (хотя здесь я скорее согласен, нечего в куки пихать то, что должно одну конкретную страницу защищать, проще на каждой странице отдельное скрытое поле выделять).

3. Про Uri — кэп, ты ли это? А ты точно освоил 100500 роутеров, чтобы так говорить?

4. Про HEAD запросы написана ересь, но частично пересекающаяся с правдой. Там все очень непросто, причем у каждого браузера свои тараканы — ответ тянет на целую статью, так что просто посмотрите как себя ведет гека с хед запросами и когда и зачем их делает и сделайте выводы (для экстрима можно edge пощупать, там вобще весело, и есть подозрение, что переход на хромиум градус веселья не уменьшит).

5. Обработка ошибок, вобще шик. А чегой-то она не может быть json или xml? У автора фобия на структурированные данные? Так в обычных ответах json его не смущал… Или у нас времена веб 1.0 и контент не сможет обработать json ответ с ошибкой? ой бяда, бяда.

Возможно, кому то коммент покажется слишком язвительным, но нет цели оскорбить автора. Скорее указать на однобокость его статьи. Может в обычном вебе это имеет ценность, но, например, в энтерпрайзе — за утверждение только UTF-8, только мейнстрим — бьют по голове, иногда даже кирпичом. Когда нужно подружить десяток разных сервисов — REST привлекает именно своей гибкостью и в то же время унифицированностью помноженной на неплохую возможность документирования (описать что делает эндпоинт, не сложно) и главное, сочетающей неплохую надежность.

Мало технологий позволяют сочетать в себе столь противоречивые качества. И тем сложнее дать им вменяемое описание, коль скоро они не имеют RFC. Автор замахнулся на неблагодарное дело…
За не-UTF-8, а особенно за Latin-1, в 2019 надо расстреливать на месте. Если у кого-то в ынтырпрайзе дикое легаси, то это их половые трудности, они всё равно туториалы на хабре не читают. Всем остальным читателям туториала только UTF-8. Там столько граблей и подводных камней с другими кодировками и перекодировками, что нафиг нафиг.

С остальным даже не знаю с чем спорить. Это долбаный туториал для тех, кто до сих пор первым делом отдаёт 200 ОК и вешает действия на get-запросы. Как бы количество добавлений в закладки намекает, да?
Т.е. вы не в курсе, что дотнет и ява из коробки поддерживают десяток самых распространенных кодировок (ни в asp.net ни в spring ненадо даже хвостом пошевелить, чтобы предоставить юзеру данные в той кодировке, что он попросит), так и добавление еще одной — дело десятка строк кода?

Рано вам туториалы писать. Тем более пытаться загнать REST — в искусственные рамки. Они есть, но несколько другие, чем описанные в статье.
Веб, очень мягко скажем, не ограничивается дотнетом и явой. Более того, их суммарная статистическая доля где-то на уровне плинтуса.
Зато есть куча языков, систем и просто софта, у которого большие проблемы с кодировками, особенно с не-UTF кодировками.
Также желаю вашему дотнету с явой успехов при работе в однобайтной кодировке с базой, содержащей неанглоязычные символы (а да, мир не только на английском разговаривают). Предположим, вам нужно поискать CITROЁN. Любое перекодирование, даже из UTF-8 в UTF-16, создаст очень большие и весёлые грабли.
Только вот проблема — REST не ограничен вебом (сюрприз), как веб не ограничен PHP.

Также желаю вашему дотнету с явой успехов при работе в однобайтной кодировке с базой, содержащей неанглоязычные символы (а да, мир не только на английском разговаривают). Предположим, вам нужно поискать CITROЁN. Любое перекодирование, даже из UTF-8 в UTF-16, создаст очень большие и весёлые грабли.

Видимо вы очень плохо знакомы с языками общего назначения. Ни для дотнета, ни для явы вобще не составит никакого труда работать с любой базой в любой кодировке, при наличии драйвера, конечно. Более того — разница будет лишь в паре строчек в конфиге и то только в отдельных, тяжелых, случаях.
Да и вобще, как можно приплести архитектуру(!) взаимодействия к базам данных?
Вы, видимо, очень плохо знакомы с особенностями юникода в реальной жизни. Как раз таки драйвер может доставить очень больших проблем, потому что его авторы могли иметь весьма расплывчатые представления о коллейшенах и нормализации, а поправить вы мало что можете.
Впрочем, делайте что хотите — хоть rest без http, хоть перекодирование в Latin-1.
Подскажите, пожалуйста, как обычно в Rest решается проблема, когда объект нужно отдавать не полностью.
Например, у сущности User есть поле locked типа boolean. На запрос клиента под логином администратора сервис отдаёт и принимает сущность, обновляя её полностью. При запросе клиентом под учёткой пользователя сервис не может не глядя принимать и обновлять сущность User, так как у пользователя нет прав на редактирование поля locked.
В rest никак не решается. Какие поля кому отдавать, кому разрешать обновлять — это не задача rest, это задача бизнес-логики.
А как вы решаете подобные ситуации? Мне приходят на ум несколько решений, но все кажутся громоздкими в той или иной мере:
— написать для каждой сущности класс-обёртку;
— создать кастомный провайдер сущностей для запросов пользователя;
— создать отдельные URI для пользователя и администратора.
Ну, наиболее универсальный вариант — кастомные представления со своими эндпоинтами.
Для юзеров будут, например, /users/:id только для чтения и с частью полей, /personal/profile с редактированием, но только своей учётки и тоже не со всеми полями, и /admin/users с полным доступом, но не для всех.
Тоже сам по себе ничего не решает. Проверку и ограничение прав должен делать слой — сюрприз — бизнес-логики. Без этого шаловливый клиент может запросить всё что захочет.
Вот вы говорите, что «REST API» — это стандарт. Если так, то где его четкое определение, где спека? Где разбор любых нетривиальных случаев?

Ах да, вы ссылаетесь на спеку по HTTP. Да вот незадача: та спека совсем не про REST. И не про JSON. И не про то, как правильно завернуть произвольный RPC API в связку HTTP+JSON в качестве транспорта.
Принципы построения REST JSON API

При этом описание ошибки, если оно есть, приводится в теле ответа в формате text/plain (без всякого JSON).

Я не любитель апишек, которые не используют HTTP коды для ошибок, но для JSON API лучше уж 200 и JSON с индикатором ошибки в теле, чем 400 и строка.

418 I'm a Teapot

Я думал первое апреля уже прошло, с каких пор 400(и 404 в случае неверных урлов) недостаточно?
Вы призываете делать грамотно и хорошо то что по определению является одним большим костылем. REST API имеет милион проблем, многие из которых привели в комментариях. Надо только не нарушать базовые условности и делать как делают все. Возможно, когда придумают идеальный rest 2.0 то появится смысл говорить о «едином» стандарте.

Я 2 года работал с magento 2 через rest api. Познал всю боль которую только можно было представить. Это с тем учетом что api довольно продумано и выражено в прекрасном swagger. Тысячи полей и мегабайты данных и кучи условий, выборок, коллекций.
Довольно забавно потом читать учения как надо сделать 2+2 и отправить очередное name в /product.
Sign up to leave a comment.

Articles

Change theme settings