Pull to refresh

Comments 13

"Сам протокол" не "не запрещает" GET с Body. До 2014-го года RFC2616 (HTTP 1.1 Spec) декларировал что GET запрос может иметь Body, но этот Body должен быть проигнорирован сервером. Если сервер как-то обрабатывает Body, и его ответ меняется в зависимости от передаваемых в нём данных - он нарушает RFC.

После 2014-го это убрали, и заменили на "body GET запроса не имеет семантики и может вызвать реджект запроса".

Это собственно довольно заметно становится в последнее время. Всё больше библиотек просто зафейлит и исходящий GET реквест с Body (javascript fetch, Unity из тех с чем я работал), и входящий GET c Body (вот на вскидку не помню...).

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

спасибо за информацию, я как раз думала о том, как бы правильнее про это написать. теперь буду знать точно)

На редкость грамотный и доходчивый материал, спасибо! Чистый бриллиант на фоне потока наскоро слепленных постов. Хочется всё бросить и иди к вам работать;) А по теме добавить нечего, всё верно сказано. К сожалению, часто куча комментариев и несправедливое внимание достаётся пустопорожним статьям. Успехов вам и всего наилучшего!

По пункту 4: не очень хорошей практикой является отправка списков в ответе, более подробно можно тут почитать.

Так ведь их потом завернули в объект в разделе "Практика: оберни ответ в объект"

Верно, пропустил — глянул «итог практики» и перешёл к номеру 5.

Спасибо за статью, очень структурированно, буду рекомендовать коллегам. Давненько мне не хотелось оставить себе конспект статьи Хабра, моё почтение.

а не проще ли разбить запрос на два изначально? будет два гета: /products/{productId} и /products?someShit=string . я понимаю, что всё исходит из требований к данным, которые нужно поставлять на клиент, макетам и флоу юзера. но, таким образом, мы сможем минимизировать кол-во информации, которую возвращаем в общем запросе, оставив только базовую инфу. а все остальное, соответственно, выплюнем уже в запросе по конкретному обьекту, и можем туда напихать всего и побольше. ведь, если мы говорим о масштабировании, когда у нас будут разрастаться как и кол-во обьектов, так и информации о них, то неприлично, с точки зрения UX проектировать систему так, чтоб на пользователя вываливался поток информации. значит, система должна проектироваться изначально с расчетом на получение как части данных, так и полным набором, но по конкретному обьекту.

вопрос в следующем, если у нас изначально (если судить по примерам выше) обьект имеет большое (ну допустим больше 10) кол-во параметров, которые нужно возвращать, не проще ли изначально придерживаться плана с двумя гетами и обьяснить дизайнерам, продуктам и прочим, что так мы вместо одного монструозного запроса получим два поменьше, и это облегчит жизнь юзера, и накрутить будет проще новой логики по типу валидации доступов на каждый из них? я рассуждаю, с точки зрения, что дизайнеры и продукты тоже люди, и ошибаться могут, и если из-за их требований приходится создавать сложные запросы, не проще ли убедить их, что они придумали говно, и ты со стороны архитектора апихи видишь, что приходиться выкручиваться и делать один сложный запрос вместо двух попроще?

да, в случае с табличными представлениями данных, мой вопрос выше не имеет смысла, я знаю)

Если нужно вернуть результат по одному товару и список товаров, конечно нужно делать /products/{productId} и /products?someShit=string соответственно

Но в ресурсе /products и /products/{productId} неправильно возвращать список заявок - ресурс ведь про товар, а не про заявки (в статье ведь рассматривается кейс с заявками)

Можно было бы сделать /products/{productId}/requests - заявки по одному товару и /requests - все заявки

Я как раз об этом пишу. Если бы было сильное различие по бизнесу, стоит разделить, например:

  • пользователь может видеть заявки по одному товару, но не имеет доступ ко всем заявкам всех пользователей

  • на экране 1 в заявках по товару мы возвращаем 5 свойств для отображения каждой заявки, а на экране 2 со всеми заявками - по 20 + еще интеграцией что то получаем (тяжеловесная доп. логика)

Но если по бизнес-смыслу (не по требованиям, а именно по смыслу) - это все таки только фильтр - можно и объединить, как я сделала. Так прокатывает конечно не всегда, но можно попробовать в таком поупражняться.

будет два гета: /products/{productId} и /products?someShit=string . я понимаю, что всё исходит из требований к данным, которые нужно поставлять на клиент, макетам и флоу юзера. но, таким образом, мы сможем минимизировать кол-во информации, которую возвращаем в общем запросе, оставив только базовую инфу

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

Мне больше нравится такой вариант, особенно, если требуется многоуровневая сортировка

/api/users?sort[name]=ASC&sort[email]=DESC&filter[verified]=true

Круто, сохранила себе такой вариант, спасибо!

Хм.. А теперь объясните мне понятно, почему body в GET запросе это плохо?

На мой взгляд как раз портянка параметров запроса в url и является злом. Как минимум это просто не красиво визуально.

Ну и json в body запроса get весьма органичен, мы в json прекрасно объясняем бэкенду, что мы от него хотим получить. json структурирован, он прост и понятен, многомерен в отличии от плоского урла. В урле стоит указывать в каком виде это мы хотим получить: другой json, html или pdf.

get - запрос данных, endpoint - точка откуда мы получаем данные, body описывает то, что мы хотим получить, в каком объёме и с какими фильтрами.

Если в get нельзя положить текст запроса в body, то для сложных запросов приходится городить запрос post с текстом хотелки и его типом (читаем, изменяем или ещё что), по сути дублируя запросы http и потом на бэке разбирать, а что у нас вообще хотят попросить (graphql привет).

Но ведь запросы http для того и предназначены: get - запрос данных, post - отправка новых данных на сервер, put/patch - изменение данных, delete - удаление данных

Уже готовые запросы, которые много-много лет просто работают, так зачем поверх них вертеть ещё один слой абстракции, или делать костыли в виде длинных и сложных параметров в url?

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

Если смотреть юридически:

Можно вычитать из RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1:

The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.

По определению, данные должны определяться с помощью URI. Посмотрите также первый комментарий от Mnemonik, там подробнее расписано про этот RFC.

Если смотреть философски:

Думаю, что авторы RFC хотели сделать GET методы более легковесными, без Request Body для удобства использования, для облегчения передачи данных, для упрощения кэширования запроса (URL меньше байт займет, чем JSON с теми же параметрами).

Возможно еще для "ошибки от дурака" и более простой поддержки разделения вносить изменения/не вносить изменения: нет Request body - точно идешь по второй ветке, и никакой GET на базу не влияет.

Но это, честно говоря, мои личные домыслы, не судите строго

Если по факту:

Как уже было сказано, в статье и комментариях, Request Body просто отваливается по пути следования GET запроса. И тут против танка не попрешь, как говорится, приходится смириться и принять это за правило.

По моему опыту Request URI покрывает 90% потребностей по передаче параметров. Из основных недостатков - отсутствие типизации и обязательности. Но в остальном, смотрится довольно лаконично. А в более сложных кейсах уже приходится использовать POST.

Либо сначала сохранять POST запросом параметры, получать их айдишку, и по этой айдишке направлять GET запрос - заморочено, но может принести свои бонусы

Sign up to leave a comment.