Email or username:

Password:

Forgot your password?
rayslava

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

В смысле я тут периодически вижу горение, когда сервис возвращает 200, а внутри {"error": "go fuck yourself"}. И с моей точки зрения это вообще выглядит абсолютно нормально, потому что HTTP слой работает, сервер в норме, запрос дошёл, ответ вернулся. А вот то, что в запросе была написана херня, это вообще ни разу не проблема сервиса.
Но в комментах к каждому такому треду обязательно найдётся эксперт, который скажет, что нельзя возвращать двухсотый код при ошибке.

А я вот реально не понимаю этой проблемы. Скажем, у нас внутренние сервисы (типа гитхаба) по той же логике работают.
Если сервис начал пятисотить — надо срочно жаловаться овнеру сервиса.
Ну для четырёхсотых — возможны варианты. Скажем, я регулярно наступаю на 429, но тут я сам виноват, да.

А вот @skobkin говорит, что принято возвращать ОШИБКУ, если что-то пошло не так.

Но я вот сейчас пилю сервис на axum, и там когда что-то реально ИДЁТ НЕ ТАК, типа сервер возвращает 404, то падение происходит на уровне middleware, и ты это обрабатываешь реально как exception. Ну то есть проблема уровня «Хозяин, там сломалась труба, по которой ходили запросы!». А если ты просто запросил что-то не то, и тебе вернулась ошибка, то ты получаешь самый обыкновенный Result, и обрабатываешь его, как Result: там может быть ответ, а может быть ошибка, но это именно логическая ошибка, не ошибка транспортного слоя.

Для меня реально немного диковато выглядит вот этот прикол с тем, что сервер тебе возвращает 401, если ты запросил то, что тебе запрещает бизнес-логика, а не попробовал отправить запрос в эндпоинт чужого сервиса.

#дыбр #dev #web

27 comments
Alexey Skobkin

@rayslava
Если тебе сервер вернул 401 на запрет бизнес-логики, то это странно. Потому что это код про аутентификацию. А если уж говорить про то как нередко делают, то "запретила логика" - это авторизация. И тогда это скорее 403 если уж маппить на HTTP.

rayslava

@skobkin да какая разница. Ну вот вернул он мне 401 , если я не залогинен.
Но это же не ошибка сервиса и не ошибка клиента, это ошибка юзера.
С моей точки зрения должно вернуться что-то типа 200 "Залогинься, мразь"

А 401 должно вернуться, когда «Что ты за приложение? Я тебя не звал! Иди на селф-хостед»!

⚛️Revertron

@rayslava Ну не, мне кажется, не важно кто сгенерировал ошибку внутри твоего сервера, надо возвращать понятные HTTP-коды.
Их не зря придумывали.

@skobkin

Alexey Skobkin

@Revertron @rayslava
Ну это зависит от парадигмы опять же.
Коды изначально придумывали для другого.
Но потом, например, появлялись штуки вроде REST, которые подразумевают, что этот фреймворк может использоваться и для виртуальных бизнес-ресурсов, а не только физических файлов в ФС.

Alexey Skobkin

@rayslava
Ну вот штука в том, что во многих ситуациях HTTP стал частью протокола/соглашения API.
Неотъемлемой. Перестав быть только транспортом.

И в общем-то транспортом если уж совсем угорать будет TCP. А HTTP - это вполне себе "фреймворк" для других слоёв вроде приложения стал.

Если воспринимать API расширением HTTP, а не приложением использующим как транспорт - всё уже не так однозначно.

tuenut

@skobkin @rayslava на Вики написано, что это application layer, не транспорт.
В rfc тоже

tuenut

@rayslava @skobkin а кто должен сгенерировать 401?
Я понимаю так (я могу ошибаться), если аутентификацию проверяет сервис и аутентификация не предоставлена/не прошла, сервис должен послать нахер. Почему для этого не использовать код ошибки, который существует, при том, что это именно ошибка обработки запроса - ресурс закрыт аутентификацией?
В то время как 200 сообщает о том, что запрос успешно обработан, то есть выполнена некоторая полезная нагрузка.

tuenut

@skobkin @rayslava 401, если нет аутентификации или она не верная - мы не можем проверить, что тот, кто к нам пришел, это действительно он. Если же аутентификация есть и мы можем подтвердить пользователя, но ему это нельзя делать, тогда уже 403.
То есть, если код ошибки возвращает сервис, то 401 и 403 должны быть выброшены на разных уровнях обработки запроса.

Max

@rayslava @skobkin
Глядишь, когда-нибудь вернемся к API на базе RPC... Тот же JSON-PRC я бы назвал незаслуженно забытым...

Правда к SOAP возвращаться нет желания )))

E23

@rayslava @skobkin а для какой ситуации бы ты использовал 401 код?

D:\side\

@rayslava мне кажется, что тут есть разумный подход с точки зрения "ленивой архитектуры" – создавать новые уровни абстракции не раньше, чем от них появится структурная польза.

Здесь это выражается в том, что если для всей семантики бизнес-интерфейса есть встроенные механизмы её донесения в HTTP, то в отдельном протоколе *поверх* HTTP просто нет необходимости, и для такого протокола будет очень простой клиент.

Но "вылезающие за пределы" части могут обострять вопрос отдельности этого слоя.
Отправка запросов пачками, скажем. HTTP так не умеет, там строго один запрос/ответ, статус один сразу на всё.

Если взаимодействие по HTTP возвращает много статусов, то ответ HTTP это "э-э-э, 207, мульти-статус, без понятия чё внутри", что зачаток нового протокола, наследующего семантику HTTP. Для WebDAV это оказалось неплохим решением, например.

И нельзя на базе ответа на первый запрос отправить в той же пачке несколько новых (GET пост + комменты поста), в самом HTTP про это ничего нет.

@skobkin

@rayslava мне кажется, что тут есть разумный подход с точки зрения "ленивой архитектуры" – создавать новые уровни абстракции не раньше, чем от них появится структурная польза.

Здесь это выражается в том, что если для всей семантики бизнес-интерфейса есть встроенные механизмы её донесения в HTTP, то в отдельном протоколе *поверх* HTTP просто нет необходимости, и для такого протокола будет очень простой клиент.

Sheri Gulam

@rayslava А когда ты запрашиваешь страничку, которой нет, по твоему мнению надо возвращать 404, или 200, но внутри странички писать, что это на этой странтчке ничего нет?

В каком-то смысле, это ведь тоже не ошибка, всё работает.

κρ🦥μγ

@rayslava

Внутри концепта REST коды значимые, но если ты не принципиальный, то похуй, строй свой протокол

Umnik

@rayslava @skobkin правильно возвращать то, что уже возвращаете, лул.

Alexey Skobkin

@umnik @rayslava
То есть если это новая система, то правильно ничего не возвращать вообще? :philosoraptor:

Umnik

@skobkin @rayslava в новой - договаривайтесь. Сам я за стандарты, просто потому что новый член команды сразу будет понимать, что происходит. Но верю, что возможны ситуации, когда можно отвечать 200 на всё. От "надо СЕЙЧАС" до "чтобы задолбать скрипт кидди".

Если делаешь для внешнего пользования, то только стандарт, разумеется.

Alexey Skobkin

@umnik
@rayslava пишет не про команду, а про то, как надо делать "вообще". Ну, то есть в индустрии.

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

> Если делаешь для внешнего пользования, то только стандарт, разумеется

Так вот а что стандарт? Вопрос-то в этом.

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

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

@umnik
@rayslava пишет не про команду, а про то, как надо делать "вообще". Ну, то есть в индустрии.

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

> Если делаешь для внешнего пользования, то только стандарт, разумеется

Umnik

@skobkin хттп - это протокол. Вот тебе сотые, вот пятисотые. Воспринимаю только так и завожу баги в своих проектах, если иначе. @rayslava

Roman

@umnik @skobkin @rayslava а что, не нравится когда вернулось 200 и в ответе json с описанием ошибки? :)

Umnik

@3draven нет, не нравится. Но прям такого у меня никогда и не было. А вот отдавать 500 вместо 400 - это прям было @skobkin @rayslava

Alexey Skobkin

@umnik @3draven @rayslava
Это не "отдавать 500 вместо 400", а "ебланы не смогли в валидацию и сломались от неожиданного значения" 😁

У меня такое тоже было, лол.

Umnik

@skobkin это ты причину описываешь. Мы все её понимаем. Но для заведения дефекта были условия, что на плохой запрос должен быть ответ "плохой запрос". То есть с точки зрения "результат проверки" это именно 500 вместо 400. А под капотом да, типичная проблема, когда просто передали без проверки, а БД ругнулась на вставке, например. Просто для заведения баги это не важно [в той структуре организации было] @3draven @rayslava

Alexey Skobkin

@umnik @rayslava
Воспринимаешь только как?
Я не шучу, я размышляю в двух парадигмах сразу. Если оторваться от привычной, то вопрос вполне имеет смысл.

Umnik

@skobkin только как протокол. То есть вот методы, вот статус коды. Не требую прям всё разнообразие поддержать, но нулевые отдавать только по делу. @rayslava

Alexey Skobkin

@umnik @rayslava
Ну так методы и коды - они про доступ к ресурсам.
А какой уровень абстракции является ресурсом?

Что если для тебя ресурсом является сам эндпоинт, а не то, что он может тебе отдать после какой-то работы?

Плюс есть ведь дискуссии в стиле "надо ли возвращать 404 если ты обратился по id, которого нет", ведь на уровне протокола HTTP (без учета тела) это будет неотличимо от того, что ты просто пришел мимо эндпоинта ☝️
Но это противоречит идее "маппим все как можем на коды HTTP".

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

P.S. Мы тут не обязательно говорим про Rest. В его рамках-то как раз бизнес-сущности подразумеваются HTTP-ресурсами.

@umnik @rayslava
Ну так методы и коды - они про доступ к ресурсам.
А какой уровень абстракции является ресурсом?

Что если для тебя ресурсом является сам эндпоинт, а не то, что он может тебе отдать после какой-то работы?

Плюс есть ведь дискуссии в стиле "надо ли возвращать 404 если ты обратился по id, которого нет", ведь на уровне протокола HTTP (без учета тела) это будет неотличимо от того, что ты просто пришел мимо эндпоинта ☝️
Но это противоречит идее "маппим все как можем на коды HTTP".

Umnik

@skobkin
Каждый участник в цепочке будет эндпоинтом для меня. Каждый промежуточный узел путешествия запроса по http должен подчиняться одним и тем же правилам.

404 - это статус код. Уточнения - в теле. Не надо его не учитывать. И я буду настаивать на таком поведении до тех пор, пока не получу объяснение, почему так нельзя. Кроме "ну а что такого?"
@rayslava

Alexey Skobkin

@umnik @rayslava
А никто и не говорит, что так нельзя.
Другое дело что так "можно", а не "нужно".

То есть "должен" мне тут не очень понятно.

В целом когда Слава меня спрашивал, я сказал, что это скорее считается правилом хорошего тона. В среднем по больнице.

Однако я вполне могу понять другую позицию. Она не лишена смысла.

Go Up