Comments 125
Для шифрования данных в JSON-RPC используется JSON.Простите, это как?
Я вот помню как-то во время одного собеседования меня задали такой вопрос: «Вот вы написали в своем резюме, что знайте REST․ Ответьте пожалуйста, какой HTTP код вы получите, если при запросе к RESTful сервису ресурс не найден?».Возможно, от вас хотели, чтобы вы объяснили разницу между 404 и 410.
Что-то нелогично выходит.
Чтобы распределенная система считалась сконструированной по REST архитектуре, необходимо, чтобы она удовлетворяла следующим критериям [...] Как вы уже заметили в этих пунктах ничего не сказано про GET, PUT, POST и DELETE запросы, шифрование JSON, HTTP и т.д.
Далее:
Давайте рассмотрим модель RMM (Richardson Maturity Model) Леонарда Ричардсона.
Уровень 0: Один URI, один HTTP метод.
Откуда вообще взялся HTTP? Мы же выяснили, что HTTP не обязателен для REST… или нет?
Как вы уже догадались, такими веб-сервисами являются протоколы XML-RPC и SOAP.
Эмм. SOAP, знаете ли, не REST. Так зачем оценивать SOAP-сервис по REST-классификации?
Другими словами, какой метод вы будете использовать для каких операций, уже вопрос правильного использования протокола HTTP․
С вводом разных HTTP методов вводится также необходимость возвращения правильных HTTP статус кодов. Например, на запрос создания встречи, если она создана, то должен быть возвращен код 201. Если в течении ваших действий кто-то уже регистрировался на выбранный день и час, должен быть возвращен код 409 conflict и т.д. Опять же, тут дело в правильном использовании протокола HTTP․
… и как определить, какое использование "правильное"?
HATEOAS (Hypertext as the Engine of Application State), требование которое на мой взгляд обязателен для гипермедиа, но насколько это актуален для веб служб — не знаю.
Вы не знаете, насколько это требование актуально для веб-служб, но все равно утверждаете (позже), что именно этот уровень говорит о том, что сервис — RESTful. Хм...
А если вы разрабатывайте что-то вроде amazon, у вас должны быть несколько тысяч клиентов, о которых вы понятия не имейте, то с этим наверное наилучшим образом справиться «старик».
А вот теперь — хороший вопрос: какой же уровень RMM у амазоновских сервисов?
Ну и самое главное.
REST является архитектурой который был предложен в 2000-ие годы Роем Филдингом в его диссертации «Architectural Styles and the Design of Network-based Software Architectures»
Нет. Диссертация Филдинга описывает архитектурный стиль, а не архитектуру.
REST is a hybrid style derived from several of the network-based architectural styles described in Chapter 3 and combined with additional constraints that define a uniform connector interface. [Chapter 5]
An architectural style is a coordinated set of architectural constraints that restricts the roles/features of architectural elements and the allowed relationships among those elements within any architecture that conforms to that style. [Chapter 1]
Q. Откуда вообще взялся HTTP? Мы же выяснили, что HTTP не обязателен для REST… или нет?
A. Если речь идет про REST, то да, HTTP не обязателен. Но если речь идет про модел RMM, то тут HTTP уже обязателен.
RMM — это модель, который строен на основе RESTЯ. Я могу сам создать какой-то модель,
который будет удовлетворять всем пунктам REST и назвать его моделю Шурика. Если веб сервис будет удовлетворять этой модели, то он тоже будет RESTfull.
Единственное отличное будет, что про модель Шурика буду знать только я, а RMM является общепринятым.
Q. Эмм. SOAP, знаете ли, не REST. Так зачем оценивать SOAP-сервис по REST-классификации?
A. Поскольку SOAP — это реализация веб сервиса, а REST — это архитектурный стил.
Вы же можете взять любой класс и сказать является ли он синглтон или нет? Почти тоже самое тут.
Q. … и как определить, какое использование «правильное»?
A. Тут нет спецификации, нет конкретного определения, что так правильно, а так нет.
Нужно просто, чтобы бизнес логика соответствовала описанию статус кодов, вот например:
201 Created
The request has been fulfilled, resulting in the creation of a new resource.
Если этот код будет возвращен при удалении записи, будет неправильно.
Q. Вы не знаете, насколько это требование актуально для веб-служб, но все равно утверждаете (позже), что именно этот уровень говорит о том, что сервис — RESTful. Хм…
A. По модели RMM, если ваш сервис не поддерживает HATEOAS, то его можно считать только частично RESTful.
На счет актуальности — это мое субьективное мнение. Инымы словами, я не знаю насколько актуально иметь полноценню RESTfull службу.
А HATEOAS — это обязательное ограничение для REST.
Q. А вот теперь — хороший вопрос: какой же уровень RMM у амазоновских сервисов?
A. Надо проверить. Что-то мне кажется, что HATEOAS они не поддерживают.
Q. Нет. Диссертация Филдинга описывает архитектурный стиль, а не архитектуру.
A. Согласен. Правильнее будет «Архитектурный стиль».
Если речь идет про REST, то да, HTTP не обязателен. Но если речь идет про модел RMM, то тут HTTP уже обязателен.
А какой нам интерес в модели, которая налагает более строгие ограничения, хотя раньше вы несколько раз говорили, что вас удивляет, когда спрашивают про эти ограничения?
RMM является общепринятым.
Является ли?
Вы же можете взять любой класс и сказать является ли он синглтон или нет?
Конечно, не могу — если, например, единственность его экземпляра обеспечивается другими средствами.
Но вопрос не в том, могу ли, а зачем.
Тут нет спецификации, нет конкретного определения, что так правильно, а так нет.
Нужно просто, чтобы бизнес логика соответствовала описанию статус кодов, вот например:
201 Created
The request has been fulfilled, resulting in the creation of a new resource.
Если этот код будет возвращен при удалении записи, будет неправильно.
Если нет конкретного определения, что "правильно", то откуда вы берете "неправильно".
И, что характерно, больше половины виденных мной дебатов вокруг REST как раз сводились к "как же правильно имплементировать HTTP".
А HATEOAS — это обязательное ограничение для REST.
Дело за малым — найти способ формально определить, поддерживает ли тот или иное приложение HATEOAS.
Помимо того что REST это не стандарт, а принципы построения архитектуры, в отличие от веб-сервисов, для меня видится ключевым отсутствие хранения состояния. Именно это я и спрашиваю на собеседовании при приеме к нам на работу. Если есть понимание, что REST это строго отсутствие состояния, а веб-сервисы нет (или не всегда), то на вопрос ответили правильно (хинт для тех кто пойдет к нам трудоустраиваться :) )
для меня видится ключевым отсутствие хранения состояния
Отсутствие хранения какого состояния?
Если пойти дальше, то и взаимодействие с БД можно тоже сделать restful и вообще избавится от сессий, заменив их, к примеру, на токены.
Вообще тема скользкая, в моей логике тоже есть изъяны и всегда можно найти контрпример :) Я считаю REST подход может масштабироваться и переходить на разные уровни (необязательно речь про веб).
Состояние объекта разумеется. Если есть на сервере объект, то мы никогда не храним его состояние (изначальное или измененное) в «неразделяемых» условиях. Для примера можно взять объект «сессия». По REST подходу его нельзя хранить в in-memory на машине, а нужно передавать на «разделяемый» ресурс (БД, к примеру).
Эмм. С точки зрения REST нет никакого разделения на "сервер" и "БД", поэтому "состояние объекта" в вашем примере хранится "на сервере" (в противовес "на клиенте"). Поэтому ваш вопрос (по крайней мере, в такой трактовке) неправилен.
Не вижу ничего неправильного в вопросе, можете поподробнее?
Ох, давайте начнем сначала.
Когда вы говорите, что в REST нет состояния, что конкретно вы имеете в виду? Нет состояния чего? Нет где (напомню, наше "где" ограничивается только клиентом или сервером)?
Вот на этом, скажем, примере:
PUT /clients/1
{
"name": "Client 1"
}
< 201 CREATED
GET /clients/1
< 200 OK
< {
< "name": "Client 1"
< }
Когда вы говорите, что в REST нет состояния, что конкретно вы имеете в виду?
для меня видится ключевым отсутствие хранения состояния.
Я не утверждал, что состояния нет. Я лишь сказал, что мы его не храним на неразделяемых ресурсах. Или выражаясь другим языком, подсказанным f0rk, сессисонно (или per-request или по-запросно, как хотите).
В этом примере, мы создали/отредактировали объект «Client 1». Если нам этот объект опять понадобится мы запросим его с сервера и будем с ним работать, а не с тем объектом который мы создали. Если мы говорим о веб сервисах, то в них не описано (протоколом точно, в договоренностях не всегда) как нам поступить в этом случае — работать с созданным или запросить новый.
В этом мое понимание этого принципа. У вас есть контрпример или свое видение?
Если нам этот объект опять понадобится мы запросим его с сервера и будем с ним работать, а не с тем объектом который мы создали.
Кто "мы"? Клиент? Тогда это совершенно точно не так, REST нигде не накладывает таких ограничений.
Более того, механизм конфликтов на основе If-Not-Modified-Since
намекает нам на то, что в голове держали строго обратный сценарий. И это логично, потому что каждый раз перезапрашивать объект, особенно в условиях пропадающего соединения, очень дорого.
Во-вторых, при чему тут If-Not-Modified-Since и в целом HTTP? Транспорт может быть любой.
Ну и в-третьих, так и не увидел ответа на свой вопрос. Пока вижу кучу нападок на мое мнение, без контраргументов.
Причем и на сервер и на клиент, раз иного не упомянуто.
Вообще-то у Филдинга явно сказано: "We next add a constraint to the client-server interaction: communication must be stateless in nature, as in the client-stateless-server style of Section 3.4.3". Так что ограничение stateless накладывается только на сервер, а не на клиент. Дальше, идем в 3.4.3: "The client-stateless-server style derives from client-server with the additional constraint that no session state is allowed on the server component."
Таким образом, диссертация Филдинга, если мы ее берем за основу, накладывает на REST только одно ограничение по хранению состояния: сервер не должен хранить сессионное состояние.
(обсуждение, является ли кэш сессионным состоянием, смотрите ниже)
Ну и в-третьих, так и не увидел ответа на свой вопрос. Пока вижу кучу нападок на мое мнение, без контраргументов.
Вы просто пропускаете контраргументы.
(1) ничто не запрещает клиенту хранить любое состояние (более того, Филдинг явно пишет "Session state is kept entirely on the client"). Здравый смысл подсказывает нам, что нет никаких проблем с тем, чтобы хранить созданный бизнес-объект на клиенте, там его обновлять, и высылать обновления на сервер (получая в ответ уведомления о конфликтах, если такие случились).
(2) ничто не запрещает серверу хранить бизнес-состояние (сущностей ли, процессов ли), потому что иначе эти сервера будут (в основном) бессмысленны. Рассуждения "мы храним состояние не на веб-сервере, а в БД" находятся строго за пределами REST, потому что для REST есть только пара "клиент-сервер" (где, в данном случае, "сервером" выступает "веб-сервер"), и где именно сервер хранит состояние, значения не имеет.
Так что обсуждение, какое же именно состояние в REST допустимо, а какое нет, — тема для длинного вдумчивого обсуждения.
(
Традиционный пример здесь, на самом деле, это какой-нибудь пейджинг. Пример с состоянием-на-сервере — это POST /search/nextPage
, в то время как REST-совместимый пример — это POST /search?page=2
(с поисковым запросом в теле)
)
communication must be stateless in nature
То бишь, где они расположены неважно, сам процесс взаимодействия между сервером и клиентом должен быть stateless. Ваши референсы далее касаются хранения сессии, а не состояния объектов.
По вашим аргументам:
1) Действительно ничто, потому что REST это принципы, а не четкий протокол. Вы можете делать так, а можете не делать, руководствуясь, в т.ч. «здравым смыслом». В моем понимании stateless должен быть на всех этапах выполнения бизнес-процесса.
2) Мое мнение, эти принципы масштабируемы под разные уровни. Браузер <-> веб-сервер <-> БД, почему нет? На каждом из звеньев можно соблюдать эти принципы. Где именно хранит важно для соблюдения stateless.
Так что обсуждение, какое же именно состояние в REST допустимо, а какое нет, — тема для длинного вдумчивого обсуждения.
Да, как я упомянул выше, тема очень скользкая и немало копий сломано :) Будет интересно где-нибудь обсудить.
Ваши референсы далее касаются хранения сессии, а не состояния объектов.
А про состояние объектов не сказано ни слова. Значит, к ним эти ограничения не относятся.
В моем понимании stateless должен быть на всех этапах выполнения бизнес-процесса.
Это невозможно, потому что бизнес-процесс и характеризуется состоянием.
На каждом из звеньев можно соблюдать эти принципы.
Stateless (в вашем понимании) БД? Невозможно.
Где именно хранит важно для соблюдения stateless.
Вы сейчас явно противоречите тексту Филдинга о том, что сервер — черный ящик.
А что, ваш второй пример можно закэшировать? Почему он масштабируется лучше, чем первый?
Но в зависимости от реализации — можно, если переход по такому URL не подразумевает изменения текущей страницы для пользователя.
… но он-то подразумевает, это nextPage.
Ну а масшабируется, потому что ?sessionId=Vasya и ?sessionId=Petya могут быть перенаправлены на обработку разными серверами или закешированы разными прокси.
… и чем это отличается от куки, на которых те же сессии делаются обычно?
… но он-то подразумевает, это nextPage.
Зависит от реализации. Это просто может быть указатель на следующую страницу без изменения состояния текущей. Или по-другому — next page может быть точкой отсчета, а current = next-1.
… и чем это отличается от куки, на которых те же сессии делаются обычно?
Тем, что запросы с куками не кешируется и не масштабируется инфраструктурой web, теми же прокси-кэш серверами, например.
Это просто может быть указатель на следующую страницу без изменения состояния текущей.
Следующую относительно чего?
Тем, что запросы с куками не кешируется и не масштабируется инфраструктурой web, теми же прокси-кэш серверами, например.
Хм, точно ли?
(скажем, ARR по кукам как раз делает sticky session)
Следующую относительно чего?
Относительно текущей.
Хм, точно ли?
(скажем, ARR по кукам как раз делает sticky session)
В данной нам реализации web ресурс идентифицируется по URL, а не по кукам и URL. Поэтому запрос не кешируется правильно.
ARR? IIS Application Request Routing? Так это приблуда IIS, какое отношение оно имеет к инфраструктуре web?
Относительно текущей.
А текущая как определяется?
В данной нам реализации web ресурс идентифицируется по URL, а не по кукам и URL. Поэтому запрос не кешируется правильно.
Одно дело — как он идентифицируется, другое — как он кэшируется. Скажем, достаточно очевидно, что нельзя в ответ на запросы к одному и тому же URL отдавать закэшированные ответы с разным Content-Type
, нет? Вот и с куками то же самое.
Vary: Cookie
, да.
ARR? IIS Application Request Routing? Так это приблуда IIS, какое отношение оно имеет к инфраструктуре web?
Такое же, как и другие проксирующие/кэширующие маршрутизаторы.
А текущая как определяется?
По sessionID
Vary: Cookie, да.
Спасибо про vary header. Да, с этим хедером запросы будут нормально кешироваться. Значит, проблемы с куками не в кешировании и масштабировании, как я предполагал. Филдинг указывает на другие проблемы с куками, связанные с mis-communication между сервером и клиентом и нарушением приватности из-за того, что они аттачатся к любому запросу (6.3.4.2 Cookies). Решением предлагает использовании context-setting URI. То есть pages/current?sessionId=Vasya будет все-таки REST-ful.
По sessionID
То есть хранится на сервере, может быть изменено другим запросом и так далее. Не, разницы нет никакой — это то же самое сессионное состояние, о котором пишет Филдинг.
То есть pages/current?sessionId=Vasya будет все-таки REST-ful.
Сессионное состояние на сервере противоречит требованию stateless как оно описано в диссертации. Применима ли эта диссертация сейчас — вопрос другой, но пока мы вроде как условились считать ее за исходный камень.
То есть хранится на сервере, может быть изменено другим запросом и так далее.
Чем состояние сессии отличается от любого другого состояния, хранящегося на сервере? Состояние сессии может трактоваться так же как и любой другой ресурс? Как насчет этого:
PUT /session/Vasya
< 201 CREATED
GET /session/Vasya
< 200 OK
< {
< «current-page»: "/session/Vasya/current-page"
< }
POST /session/Vasya/current-page
+1
<200 OK
Не, разницы нет никакой — это то же самое сессионное состояние, о котором пишет Филдинг.
После The client-stateless-server style derives from client-server with the additional constraint that no session state is allowed on the server component. он пишет уточнение Each request from client to server must contain all of the information necessary to understand the request. Тут под session state имеется ввиду, некое неявное из запроса состояние, которое образуется на сервере в результате серии запросов от одного и тоже клиента. В результате чего отдельно взятый запрос из этой серии будет непонятен серверу. Но что непонятного для сервера в запросе session/vasya/current-page или pages/current?sessionId=Vasya?
Чем состояние сессии отличается от любого другого состояния, хранящегося на сервере?
Семантикой, вестимо. И именно в этом месте и начинаются драки за то, что считать stateless, а что — нет.
Тут под session state имеется ввиду, некое неявное из запроса состояние, которое образуется на сервере в результате серии запросов от одного и тоже клиента.
Проблема в том, что вы здесь додумываете, что же именно имеет в виду Филдинг. Вы можете додумать одно, я могу додумать другое, а никакого формального определения нет. Отсюда и дискуссии (включая, собственно, всю эту).
В результате чего отдельно взятый запрос из этой серии будет непонятен серверу.
Что непонятного в запросе?
GET current-page
Session: vasya
Проблема в том, что вы здесь додумываете, что же именно имеет в виду Филдинг. Вы можете додумать одно, я могу додумать другое, а никакого формального определения нет.
Там явно сказано, что имеется ввиду: Each request from client to server must contain all of the information necessary to understand the request..
Что непонятного в запросе?
Все понятно. И это будет REST-ful, если только session header не будет цепляться к каждому запросу без необходимости, как это делают куки, и добавить Vary:Session. Филдинг описывает проблему с куками ни как-то, что они связаны с user-сессией, а именно: The problem is that a cookie is defined as being attached to any future requests for a given set of resource identifiers, usually encompassing an entire site, rather than being associated with the particular application state (the set of currently rendered representations) on the browser.
там явно сказано, что имеется ввиду: Each request from client to server must contain all of the information necessary to understand the request..
Это не определение сессионного состояния, это определение того, что должен содержать клиентский запрос. И оно нестрогое, потому что формально любой запрос с куками ему соответствует.
Все понятно.
Ну вот видите. Значит, у нас нет никакого формального критерия для различения сессионного состояния.
И это будет REST-ful, если только session header не будет цепляться к каждому запросу без необходимости
Из какого пункта описания REST architectural style это следует?
Это не определение сессионного состояния, это определение того, что должен содержать клиентский запрос.
Это единственное ограничение, указанное Филдингом. Значит, все остальное — позволяется.
И оно нестрогое, потому что формально любой запрос с куками ему соответствует.
Соответствует. Проблема кук не в state.
Из какого пункта описания REST architectural style это следует?
Ни из какого. REST тут не нарушается. Мой fail.
Что делать, если установка current-page не была произведена?
404
и это неверный ответ в рамках REST.
потому как current-page роде как иеднтификатор ресурса, но он зависит от предыдущих запросов. и может каждый раз указывать на другой ресурс
Я пожалуй соглашусь, что:
GET current-page
Session: vasya
все-таки не REST (как и с куками), но не потому что:
он зависит от предыдущих запросов. и может каждый раз указывать на другой ресурс
Этот момент уже обсуждался выше.
А потому что неуверен, что так будет правильно:
PUT current-page
Session: vasya
PUT current-page
Session:petya
Также нарушено HATEOAS.
То есть наличие session-id в URL только REST-ful.
то, что его результат зависит от предыдущего
Формально, не от предыдущего, а от набора предыдущих операций с сервером:
POST search
POST search/nextPage
GET item/10
GET item/11
PUT item/11
GET item/12
DELETE item/12
GET item/13
GET item/14
GET search/currentPage
А в этом смысле уже почти любой запрос "непонятен":
GET item/1
< 404
PUT item/1
< 201
GET item/1
< 200
PUT item/1
< 409
DELETE item/1
< 204
GET item/1
< 404
Тут ведь тоже результат запроса зависит от предыдущего, не так ли?
Что делать, если установка current-page не была произведена?
Определяется бизнес-правилами, очевидно — точно так же, как и "что делать, если обновляют ресурс, которого не существует" и так далее.
Когда вы создаете ресурс, то в ответ получаете 201 и линку на ресурс с уникальным идентификтором.
В диссертации Филдинга прямо так и написано?
А вот current-page не идентификатор и однозначно не мапится на ресурс, потому это нифига не REST
А в POST search
что ресурс? А в POST /builds/15/enqueue
?
Даже более занятный вопрос: что ресурс в GET /queuedEmails
?
Ну я без понятия где вы набрали таких запросов. Теоретически
POST /search должен содержать атрибуты ресурса в теле запроса, который требуется создать.
Почему это? "The action performed by the POST method might not result in a resource that can be identified by a URI" (RFC 2616, 9.5) И позже: "The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations."
По поводу Филдинга, ознакомьтесь с Section 5.2
Там нет ни слова про обязательные коды ответов HTTP.
Я уже процитировал высказывание о ресурсах из той же диссертации. Совершенно не понятно, из какого именно тезиса в диссертации вы делаете вывод, что /search
— не ресурс (или что POST
на него обязан создавать новую сущность).
(BTW, не архитектуру, а архитектурный стиль)
любой клиент запросив /search должен получить ровно тоже самое
Это, как мы понимаем, противоречит здравому смыслу, причем не важно, /search
у вас или /books
.
Но както так вышло, что обычно постом создают ресурсы, а гетом читают.
Это если у вас ресурсы имеют CRUD-семантику (да и то не обязательно). Но ей же дело не ограничивается.
Но условно, если есть 2 юзера с правом чтения этого ресурса, то оба должны получать этот ресурс при одинаковом запросе до тех пор, пока ресурс не будет удален. При этом второму юзеру не нужно повторять всю цепочку запросов, которая привела ресурс в определнное состояние, чтобы это сосотояние в итоге увидеть.
Ну так и /search
ведет себя так же — все юзеры, которые имеют право на эту операцию, получают некий ответ. То, что этот ответ зависит от пользователя — так это технически ничем не отличается от разграничения по правам.
Соответственно, все это обсуждение скатывается к семантике, которая у Филдинга (естественно), не формализована.
Если ресурс был удален, а потом создан новый с таким же содержимым — это всеравно уже другой ресурс, и у него должен быть свой уникальный идентификатор.
Это, кстати, неверно. Цитату про идентификаторы и семантику я уже приводил.
Как можно не понимать, что не должно быть зависимости от цепочки предыдущих запросов?
Очень просто: нет определения "зависимости". Результат следующего запроса зависит от предыдущих проведенных? Так это нормальное поведение нормальной бизнес-системы.
Аналогии с подменой — некрасиво.
Результат запроса "покажи начисления за последний месяц" будет зависеть от того, какие начисления были проведены в последнем месяце (=какие запросы "сделай начисление" были выполнены)?
Вот если бы в вашем примере с currentPage было, что Петя устанавливает currentPage, а Вася запрашивая currentPage увидит то, что установил Петя
Ну нет. Мы же уже выясняли, что один и тот же ресурс может иметь разные представления для разных пользователей. Авторизация, бизнес-ограничения, вот это все. Поэтому максимум, которого вы можете ожидать — это то, что когда Вася установил currentPage, Вася потом его и увидит… но ведь это так и есть.
Окей, только тот бухгалтер, который зп вам нащитал сможет для вас сформировать отчет. А другой не сможет.
Так иногда бывает, вы не поверите.
Вопросы авторизации/прав ортогональны существованию ресурсов.
Да, ортогональны. Но они влияют на то, как ресурс отображается конечному клиенту, поэтому игнорировать их нельзя (иначе получаются ошибки вида "Вася увидит то же, что и Петя").
Просто вы получите ответ в виде: "доступ запрещен, обратитесь к администратору".
… или, если используется соответствующая политика безопасности, "ресурс не найден". Потому что раскрытие информации о существовании ресурса — потенциальная уязвимость.
Ну да, к разговору о "не ресурс":
The definition of resource in REST is based on a simple premise: identifiers should change as infrequently as possible. Because the Web uses embedded identifiers rather than link servers, authors need an identifier that closely matches the semantics they intend by a hypermedia reference, allowing the reference to remain static even though the result of accessing that reference may change over time. 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. It is then left to the author to ensure that the identifier chosen for a reference does indeed identify the intended semantics.
each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server.
Т.е. пример с nextPage правильно описывает stateless.
На сервере нет дополнительной информации (отсутствующей в запросе), которая позволила бы ответить на этот запрос как-то иначе.
На сервере нет дополнительной информации (отсутствующей в запросе), которая позволила бы ответить на этот запрос как-то иначе.
Это неправда. Если бы на сервере уже существовал ресурс с адресом /clients/1
, ответ был бы 200 OK
/204 No Content
(ну или отказ в модификации, если она запрещена).
Если бы на сервере уже существовал ресурс с адресом /clients/1, ответ был бы 200 OK/204 No Content (ну или отказ в модификации, если она запрещена).
Этот факт никак не связан с содержимым запроса, не нужно путать идемпотентность и statless
Подождите-подождите. Мы говорим не о содержимом запроса, а о состоянии. Вы только что утверждали, что
На сервере нет дополнительной информации (отсутствующей в запросе), которая позволила бы ответить на этот запрос как-то иначе.
При этом мы уверенно наблюдаем, что отсутствующая в запросе информация "на сервере этот объект есть/нет" влияет на ответ сервера.
Не согласуется.
Подождите-подождите. Мы говорим не о содержимом запроса, а о состоянии.
Мы говорим о понятии stateless в контексте REST.
отсутствующая в запросе информация "на сервере этот объект есть/нет"
Эта информация не имеет никакого отношения к сессии, любому клиенту с таким запросом при отсутствии объекта вернется 201, а при наличии 200
Мы говорим о понятии stateless в контексте REST.
… которое определено как именно?
Эта информация не имеет никакого отношения к сессии, любому клиенту с таким запросом при отсутствии объекта вернется 201, а при наличии 200
Вооот. То есть не "на сервере нет дополнительной информации (отсутствующей в запросе), которая позволила бы ответить на этот запрос как-то иначе", а "на сервере нет сессионной информации, которая позволила бы ответить на этот запрос как-то иначе".
(заметим, в случае кэша это тоже не вполне верно, но кэш мы пока обсуждать не будем)
А какая разница, все ли клиенты получат одинаковый ответ, или кто-то получит разный?
С моей точки зрения, намного интереснее то, что один и тот же клиент в ответ на две последовательные идентичные операции получит разный ответ. Это как бы явно говорит нам о наличии состояния.
На сервере нет дополнительной информации (отсутствующей в запросе), которая позволила бы ответить на этот запрос как-то иначе.Вы начали приводить пример с разграничением прав доступа и т.д., а я вам ответил, что это никак не противоречит цитате выше. Либо в запросе действительно нет никакого идентификатора сессии и т.д., но тогда и нет основания ответить на него как-то иначе, либо она есть, но тогда за сохранение состояния между двумя запросами отвечает клиент, а не сервер. Более того, один физический клиент может иметь сразу несколько сессий, но все-равно именно он отвечает за то, какую сессию использовать.
Возможно, стоит тут подойти с другой стороны. Например, как выглядит statefull API?
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
В данном случае, OpenGL явно хранит некоторое внутреннее состояние, которое зависит от ранее вызванных процедур.
1. клиент посылает запрос на аутентификацию
2. сервер проверяет кредсы и сохраняет в сессии идентификатор пользователя, возвращает (например в куки) какой-то токен, идентифицирующий сессию
3. клиент посылает запрос на создание ресурса, с указанием токена, но без указания своего единтификатора
4. сервер по идентификатору сессии достаёт идентификатор пользователя, добавляет его к данным запроса и записывает в базу
По REST на втором шаге сервер должен возвратить клиенту идентификатор пользователя, на третьем клиент передать его серверу, на четвертом сервер должен для изменения состояния использовать его, а не сохраненное в сессии.
Сессионного вестимо
То есть сервис, который внутри себя создает сессию-на-пользователя и кэширует в ней объекты для ускорения доступа — не REST?
Если кеширует — это не проблема, если изменяет из-за факта наличия сессии — то не REST
Но сессионный кеш — это все равно сессионное состояние. Получается, что какое-то сессионное состояние можно, а какое-то нельзя. Так?
если изменяет из-за факта наличия сессии — то не REST
Изменяет что?
Изменяет что?
объекты
Но сессионный кеш — это все равно сессионное состояние. Получается, что какое-то сессионное состояние можно, а какое-то нельзя. Так?
Так, это вопрос терминологии и понятия stateless в контексте REST
Так, это вопрос терминологии и понятия stateless в контексте REST
Вот и выходит, что простое "отсутствие состояния" недостаточно для понимания REST, потому что мы вот уже с десяток комментариев пытаемся выяснить, какого же состояния быть не может, а какое — может.
Примером системы, которая хранит состояние может быть например «помощник» с голосовым интерфейсом (Google Now например). Для такой системы нет ничего необычного в такой последовательности запросов:
1. Какая температура в Москве?
2. А в Самаре?
Тут видно, что «сервер» должен для выполнения второго запроса помнить, что перед этим клиент спрашивал про температуру.
В случае же REST запросы должны быть такими:
1. Какая температура в Москве?
2. Какая температура в Самаре?
Тут сервер ничего не помнит про предыдущие запросы и каждый новый запрос выполнят без оглядки на предыдущие, т.к. все необходимые для выполнения данные находятся в текущем запросе. Такой подход позволяет легче масштабировать систему, т.к. нет необходимости, что бы все запросы клиента обрабатывались только одним или несколькими серверами, у которых есть доступ к хранилищу «состоянию» клиента.
Сервер, между отдельными запросами, не хранит какого либо контекста (состояния) в котором находится клиент и какие запросы до этого он выполнял.
Если быть совсем точным, клиент не ожидает от сервера, что тот хранит такой контекст, и поэтому постоянно его шлет. Что при этом хранит сервер — его личное дело, до тех пор, пока оно не противоречит ожидаемому клиентом поведению.
Уточнение про сессионное состояние клиента — излишнее, потому что у клиента, на самом деле, нет никакого другого состояния.
Эмм, почему у клиента нет другого состояния?
В остальном, впрочем, я склонен с вами согласиться. И это, кстати, совпадает с тезисом из Филдинга: "Each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server"
Ну а как же состояние, скажем, бизнес-процесса?
Когда клиент (программа) хранит (в памяти или локально) список заказов, сделанных пользователем — это состояние клиента или нет?
Эмм, почему эта программа не клиент REST-а?
Спасибо, но, пожалуй, не интересно.
Что же касается выполнения транзакций, то этот действительно важный и сложный вопрос в REST затронут только чуть (по сложившейся традиции затрагивать действительно важные и сложные вопросы с тем самым с умным видом, как будто и так все понятно).
По теме коммуникации в стиле REST/HTTP есть классная картинка на сайте Webmachine, как вариант описания единичной транзакции с помощью диаграммы — не к столу будет сказано — состояний.
Некоторая часть моментов, с которыми обычно сталкиваются разработчики RESTful приложений на концептуальном уровне, при решении простых задач, метафорически описана в How to GET a Cup of Coffee (ага, «нельзя просто так взять и взять»). Задачи конкуретного обновления (что, в принципе, не такая уж и экзотика для распределенных приложений), с большой вероятностью могут привести к двух- (трех-, рекурсивно-) фазным коммитам. Каково это в реализации для не очень сложного кейса про дебет с кредитом можно посмотреть, например здесь (не совсем REST, но очень близко по составу операций, буквально точностью до синтаксиса).
Конечно, в реальности, так ни кто не делает — это ни в какой бюджет. Всегда есть возможность отойти от канонов, в пользу каких-то упрощений. Как следствие, с момента изобретения, для индустрии вся эта веселуха вокруг RESTful архитектур вылилась в хренову гору человеко-часов, потраченных на разработку «подходящих» имплементаций REST-style со стороны тех кто старался что-то сделать, и гигабайты срачей в комментах со стороны тех кто пытался что-то понять.
Модель RMM состоит из 4 уровня
https://github.com/onekit/rest-tutorial
Начинающим самое оно, а pull-request-ы всегда welcome.
Copyright © 2004-2016 Fabien Potencier
Выложили на github, видимо, положив на принятые в open source вещи типа ссылки на оригинального автора, который, судя по сайту https://symfony.com/doc/master/contributing/code/license.html и является реальным автором кода, на котором базируется ваш.
Ну и уж если заниматься буквоедством, то Symfony2 является фреймворком, написанным огромным комьюнити контрибутеров. Не уместно ставить копирайт на одного Фабьена. Загляните в composer.json, там кроме Symfony2 много других зависимостей, например PHP, значит и копирайт создателя PHP следует поставить. А если уж его, то тогда и создателя С/C++, который в свою очередь использовал Ассемблер.
Кроме этого, веб-сервис сам описывает себя без каких-либо WSDL.
Это немного не так, скорее, он пытается сам себя описать, но у него ничего толком не получается.
Советую посмотреть на Swagger, там эту проблему решают по-взрослому.
А ваша служба является RESTful? Все что необходимо/обязательно знать про веб службы и REST