All streams
Search
Write a publication
Pull to refresh
4
0

Неизвестный агрессивный человек

Send message
По словам Роя Филдинга, API квалифицируется как «RESTful», если соответствует следующим ограничениям:

Ссылку на слова Филдинга приведёте?

Может лучше просто читать через GET, и тогда вас все поймут?)

А гейтвей HTTP-HTTP это не прокси?

Не знаю стандартная это практика для PUT или нет, но PUT совсем не подходит для /echo. Клиенты априори не должы получать эхи, записанные другими клиентами.

Продолжая наш вчерашний флейм. Вы написали, что /users/{user_id} более правильно, чем /me, и далее


// Получение профиля
GET /user/{user_id}
Authorization: Bearer <token>


Теперь URL запроса в точности идентифицирует ресурс, к которому обращаются, поэтому можно организовать кэш и даже заранее наполнить его;
[...]
Наконец, неочевидная польза такого решения заключается в следующем: промежуточный сервер-гейтвей, обрабатывающий запрос, может проверить заголовок Authorization и переслать запрос далее без него (желательно, конечно, по безопасному соединению или хотя бы подписав запрос).

И что


Запрос «себя» должен (обязан) пробивать кэш, поскольку иначе можно получить доступ к чьим-то чужим данным.

  1. Вряд ли гейтвей может переслать запрос серверу без Authorization: A proxy forwarding a request MUST NOT modify any Authorization fields in that request
    https://greenbytes.de/tech/webdav/rfc7235.html#header.authorization


  2. Общий кеш нельзя использовать для ответов на запросы с Authorization: A shared cache MUST NOT use a cached response to a request with an Authorization header field.
    https://greenbytes.de/tech/webdav/rfc7234.html#caching.authenticated.responses



Когда клиент запрашивает собственный профиль, не важно, через /me или /users/{user_id}, обычно он ожидает получить в том числе непубличную информацию об профиле. Такой запрос всегда будет с токеном.

Мозилла неточна. Я загуглил этот вопрос и попал на ответ от Julian Reschke, одного из авторов спецификации HTTP.


So yes, responses for a succesful PUT can have a reponse body, but normally, it does not make sense to include one. (What for?).
https://stackoverflow.com/questions/63275986/meaning-that-put-method-successful-response-has-body-in-the-mdn-document


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

Сохраняет в память и возвращает обратно, всё совершенно логично.

Да не должен он ничего сохранять, представьте что /echo является stateless по определению. Негде ему это сохранять, и незачем.


PUT может иметь тело ответа, конечно.

Моzilla ошибается? https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/PUT

Ну да. Разница в том, что GET возвращает представление адресуемой сущности, а POST не обязательно; он как раз задизайнен чтобы предоставлять доступ к сущностям, не имеющим прямого URL.

Ну, так и /echo вполне является адресумой сущностью с переменным представлением. POST задизайнен для того, чтобы его можно было использовать для любых других операций, не стандартизированных в рамках остальных методов. Как писал Филдинг, "POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”"
https://roy.gbiv.com/untangled/2009/it-is-okay-to-use-post


Вы просто говорите, что индицировать одни эффекты (немодифицируемость, идемпотентность) считаете более важными, чем другие (некэшируемость, семантика глагола).

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


Запрос «себя» должен (обязан) пробивать кэш, поскольку иначе можно получить доступ к чьим-то чужим данным. С моей точки зрения это важнее, чем индикация идемпотентности.

Так можно сказать про любой авторизованный GET запрос. Не думаю что вы предлагаете заменять все такие читающие запросы на POST просто чтобы "пробить кеш".


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

Здесь я согласен :)

Это очень странно, потому что /echo априори ничего не записывает и ничего не сохраняет; PUT заменяет представление ресурса данными представленными в теле запроса, но что, если тело запроса будет пустым; кроме этого, ответ PUT тела не имеет.


Как вы себе это представляете? Делать PUT /echo, потом GET /echo? А если один клиент сделает PUT /echo, а другой сделает GET /echo?

Я же с вами абсолютно не спорю. Я всего лишь говорю, что, обращаясь к нему таким образом, вас интересует не внутреннее представление самого ресурса echo, а результат некоторого алгоритма, на который ссылается /echo. А для этого предназначен POST.

POST, как и GET, тоже возвращает представление, а представление может представлять результат обращения к ресурсу, или представлять состояние, в которое должен перейти клиент. Такого понятия, как "внутреннее представление" (хранимое?) в HTTP нет. Когда мы делаем GET https://habr.com/ru/post/560590/, мы понятия не имеем, возвращает ли этот ресурс "внутреннее представление", результат сложных вычислений или промежуточный ответ от другого сервера. Рандомные цитаты от GPT мы тоже должны через POST получать?) Получить свой адрес по http://ip.changeip.com/ тоже? А считывать метрологические данные https://tgftp.nws.noaa.gov/data/observations/metar/stations/UKLL.TXT тоже через POST? И лицо получать https://thispersondoesnotexist.com/ тоже?


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

Я бы просто использовал для этого Cache-Control, а не подменял бы смысл запроса на POST, давая знать, что этот запрос кроме чтения может иметь другие побочные эффекты.

Скорее сервис, чем документ. Хотя он может быть ни тем, ни другим.

Зачем? Ресурс /echo семантически не предназначен ни для чего другого, кроме извлечения информации; он безопасен; он идемпотентен. Клиент или любой промежуточный агент, зная, что GET идемпотентен, может сам повторить запрос при сбоях связи. А вы предлагаете отбросить эту семантическую информацию, использовав POST. Этой заменой ничего не выиграете.

Продолжая ваш ход мыслей. Представим ресурс /echo, который в теле ответа отражает запрос обратно клиенту — со всеми заголовками, как есть. Его тоже следует использовать методом POST?

Получается, что /me не указывает на некоторую «именованную сущность», как предписывает концепция ресурса.

Вряд ли она предписывает. Наоборот, REST определяет "ресурс" как семантику, а не как значение, которое соответствует этой семантике. Давайте просто сошлемся на источники:
REST accomplishes this by defining a resource to be the semantics of what the author intends to identify, rather than the value corresponding to those semantics at the time the reference is created.
https://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm#sec_6_2_1


This specification does not limit the scope of what might be a resource; rather, the term “resource” is used in a general sense for whatever might be identified by a URI. […] This specification does not place any limits on the nature of a resource, the reasons why an application might seek to refer to a resource, or the kinds of systems that might use URIs for the sake of identifying resources.
https://tools.ietf.org/html/rfc3986#section-1.1


The target of an HTTP request is called a “resource”. HTTP does not limit the nature of a resource; it merely defines an interface that might be used to interact with resources.
https://tools.ietf.org/html/rfc7231#section-2


Resources are not storage items (or, at least, they aren’t always equivalent to some storage item on the back-end). [...] Likewise, a single resource can be the equivalent of a database stored procedure, with the power to abstract state changes over any number of storage items.
https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven#comment-743


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

Мы сейчас на второй круг зайдем :) Хорошо, я отвечу вашими же словами:


Приведём простой пример. Пусть в нашей системе есть операции получения профиля пользователя и его удаления. Мы можем организовать их разными способами. Например, вот так:
// Получение профиля
GET /me
Cookie: session_id=<идентификатор сессии>

Ресурс /me возвращает профиль пользователя, который сделал этот запрос. Выше вы предложили сделать то же самое, но через POST /me. В чем разница?

Со stateless-принципом авторизация в принципе плохо дружит, сам Филдинг это признал в ныне умершей группе рассылки на yahoo:
I should note that the big conflict between REST and security models is the fact that REST does not allow for sessions. What needs to be understood is that sessions are bad for security models too – they cause most of the denial-of-service and man-in-the-middle attacks to be possible. What is needed is an efficient, session free means of authenticating that is more secure than username/password, which is actually an easy problem to solve if you don’t try to solve all of the security problems at once. What is blocking that is the need to negotiate security mechanisms before engaging in secure communication, which is currently done within a session.
https://web.archive.org/web/20191213070235/https://groups.yahoo.com/neo/groups/rest-discuss/conversations/messages/3661

Мы не меняем предусловия, /me возвращает авторизованный аккаунт исходя из переданного токена. Вопрос остается в силе. Почему POST?

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


Все-таки, вы можете привести конкретные отличия или противоречия?

Зачем использовать POST для чтения, если для этого есть безопасный, идемпотентный GET? И чем принципиально это отличается от GET /me?

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

В REST интерфейсы не должны быть "просто стандартизированными". Ограничение Uniform Interface (является центральным) отсылает нас к четырём интерфейсным ограничениям: REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state. Ничего не напоминает?


Ключевой вывод, который следует из определения REST по Филдингу, вообще-то, таков: любое сетевое ПО в мире соответствует принципам REST, за очень-очень редкими исключениями.

Я не понимаю, каким образом этот вывод следует.


Всё, на этом определение REST заканчивается. Дальше Филдинг конкретизирует некоторые аспекты имплементации систем в указанных ограничениях, но все они точно так же являются совершенно абстрактными. Буквально: «ключевая информационная абстракция в REST — ресурс; любая информация, которой можно дать наименование, может быть ресурсом».

  1. Паттерны проектирования тоже являются абстрактными, а REST, как архитектурный стиль, стоит "на ступеньку выше": он еще более абстрактный, так как описывает стиль архитектуры приложения в целом, а не отдельную его конструкцию.
  2. Спецификации URI и HTTP определяют понятие ресурса точно так же. Предполагается, что ресурс сам может инструктировать клиентов о том, как этим ресурсом можно манипулировать (manipulation of resources through representations) и в какие следующие состояния клиент может перейти (hypermedia as the engine of application state). Ресурс, отдающий HTML-страницу с формами и ссылками работает в точности так.
  3. Кроме собственно REST, в работе Филднга есть следующий раздел Experience and Evaluation, который описывает его историю и предпосылки его возникновения.
    https://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm

наконец, code-on-demand вообще лукавое требование, поскольку всегда можно объявить данные, полученные по сети, «инструкциями» на некотором формальном языке, а код клиента — их интерпретатором.
[...]
Например, очевидно, что требование code-on-demand противоречит требованию независимости клиента и сервера — клиент должен уметь интерпретировать код с сервера, написанный на вполне конкретном языке.

Тег script является эталонным примером code-on-demand. Клиент может затребовать дополнительный код того типа, который в состоянии выполнить, а может и не затребовать. Это необязательное ограничение (и в диссертации ясно написано, почему), но в браузерах оно используется очень широко, особенно в последнее время.


Оставляя за скобками тот факт, что Филдинг весьма вольно истолковал свою же диссертацию, просто отметим, что ни одна существующая система в мире не удовлетворяет описанию REST по Филдингу-2008.

За деревьями не видно леса. Гипертекстовый веб как система сам по себе является примером такой архитектуры. Диссертация филдинга не появилась из ниоткуда — он начал описывать REST с 1994 года именно для того, чтобы формализовать основные принципы гипертекстовой сети во время его работы над стандартизацией HTTP и URI. В это же время Филдинг стал ведущим автором этих спецификаций (Тим Бернерс-Ли прекратил работать над HTTP и HTML с 1993 года, занявшись созданием W3C).


This idealized model of the interactions within an overall Web application—what we refer to as the Representational State Transfer (REST) architectural style—became the foundation for the modern Web architecture, providing the guiding principles by which flaws in the existing architecture could be identified and extensions validated prior to deployment.
Roy Fielding, Richard Taylor. Principled Design of the Modern Web Architecture


И я не могу понять тезис о разнице между REST и "REST по Филдингу-2008", который гуляет еще с ваших прошлых постов. Какие именно отличия имеются между "REST-2000" и "REST-2008"?


Как же сделать эти операции правильно с точки зрения REST? Вот так:
// Получение профиля
GET /user/{user_id}
Authorization: Bearer <token>

Каким образом клиент узнает свой user_id?

Information

Rating
Does not participate
Registered
Activity