Pull to refresh

Comments 103

Что-то я не пойму…
Во-первых, как отсутствие состояния в ограничениях Филдинга сочетается с «изменением состояния ресурса» в пункте 1?
Во-вторых, как отсутствие необходимости «беспокоиться о том, что случайно закэшируется только часть необходимой информации» сочетается с понятием гипермедиа?
Или более обще, как самодостаточность каждого сообщения из пункта 3 сочетается с понятием гипермедиа?
Отсутствия состояния у протокола обмена между клиентом и сервером. Нет, например, каких-то хендшейков, определенной последовательности запросов, ожиданий клиента или сервера, что сервер или клиент помнят какие-то предыдущие запросы или ответы.

Самодостаточность означает, что что каждое сообщение логически полное, но при этом может содержать гипермедиа ссылки на другие ресурсы.
Правильно ли я понимаю, что везде, где есть авторизация, это уже не RESTful? То есть у клиента появляется зависимость от предыдущих запросов, которое можно считать состоянием.
Современная авторизация предполагает получение от сервера авторизации сертификата на доступ к ресурсам (тикет в OAuth, например), который в дальнейшем указывается в заголовке В КАЖДОМ ЗАПРОСЕ на получение/изменение данных. Т.е., каждый запрос содержит полную информацию, достаточную для его обработки (т.о., обрабатывается без учёта какого-либо состояния). Получается честный stateless.
Извиняюсь за невнимательность, перечитав поняла, что каждый запрос независим, и ключ авторизации стоит рассматривать как дополнительный параметр запроса.
Немного не понял. А чем это отличается в плане хранения состояния от обычной авторизации, например, в PHP? При логине выдаем клиенту идентификатор сессии, клиент хранит его у себя и при каждом запросе отправляет на сервер. Сервер может проверить валидность этого идентификатора, потому что хранит сессии у себя.
Сертификат содержит идентификатор пользователя, а ид сессии — нет. Малой кровью чистый RESTful реализуется с помощью HTTP-аутентификации. Хотя лично я не считаю большим отклонением от принципов процедуру логина, если в сессиях подобных php хранить исключительно идентификатор пользователя.
Сертификат содержит идентификатор пользователя

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

А при чем тут вообще сессия? Тикеты OAuth не имеют никакого отношения к сессиям.
Сессия в PHP живёт 24 минуты.
И если есть защита от http-флуда, то, как можно подобрать ключ за это время?
Сессия живёт столько, сколько указано в настройках.
Кстати, заинтересовался, а как «современная авторизация», соответствующая HTTP REST должна решать проблему, когда приходит HTTP POST запрос с кучей данных и устаревшим тикетом?
В идеале сервер должен отдать ошибку 401 сразу после разбора устаревшего тикета, отменив приём тела запроса. Клиент при этом должен осуществить попытку обновления тикета на сервере авторизации и, если это удаётся, повторяет изначальный запрос с данными. Всё это происходит прозрачно для пользователя (т.е., время истечения валидность тикета — это не «время сессии», а «уровень безопасности, соответствующий частоте обновления тикетов»).
Коды ошибок HTTP пронумерованы так, чтобы проверки на возникновение этих ошибок происходили в порядке возрастания этих кодов (хотя это и не всегда так, но для единиц и десятков, как правило, именно так — каждый последующий номер является более специфичным).

Т.е., на сервере сначала идёт парсинг запроса (выделение имён и значений параметров, заголовков, т.п.) Если на этом этапе случилась ошибка — сервер вернёт 400 («я вообще ничего не понял, что ты спрашиваешь, и мне плевать, кто ты»). Если ошибки не было — производим этап парсинга заголовков. Если на этом этапе была выяснена невалидность тикета (просрочннность, например), то, по-сути, тикета нет и уже не важно, кто именно там в тикете указан — сервер просто не имеет права доверять его содержимому, и потому сигнализирует об его отсутствии — 401 («я не понял, кто ты»). Если же тикет присутствует и валиден, но данному конкретному юзеру запрещён доступ к данному конкретному ресурсу, то сервер возвращает 403 («запрос корректен, я понял, кто ты, но тебе запрещенно лезть к этому конкретному ресурсу»).
Что такое 401 и 403 я знаю, есть куча расшифровок и описаний в RFC. Я о другом!

Вы на ситуацию:
когда приходит HTTP POST запрос с кучей данных и устаревшим тикетом?


Предлагаете ответить с помощью 401, что в корне не верно, сами же написали, что:
401 («я не понял, кто ты»)


Вместо этого более подходящий способ: 403, т.е. ваши же слова:
403 («запрос корректен, я понял, кто ты, но тебе запрещенно лезть к этому конкретному ресурсу»)


Вполне логично, что сервер запрещает доступ к ресурсу, токен же протух!
«Протухший токен» = «отсутствующий токен» («протухшесть» токена находится за гранью понимания обработчика запросов на изменение данных — это кухня сервиса авторизации/аутентификации). Ваш вариант не позволяет различать ограничения бизнес-логики (отсутствие прав у пользователя, к примеру, о котором нужно сообщить пользователю) и необходимость отрефрешить токен (что должно произойти без уведомления пользователя автоматически). Также ваш вариант содержит и более тонкие проблемы — например, возможность «прощупать» протухшим токеном существование определённых ресурсов без доступа к ним.
>>возможность «прощупать» протухшим токеном существование определённых ресурсов без доступа к ним.
принято! Это единственный аргумент, который принуждает использовать 401, хоть это и не совсем корректно
Коды ошибок в протоколе нужны только для дифференциации стратегий их обработки, не стОит наделять их излишне глубоким смыслом («корректность/некорректностью») в отрыве от этой дифференциации. Также коды ошибок созданы так, чтобы поощрять «послойную» архитектуру сервера, обрабатывающего запросы (каждый слой архитектуры резервирует свои непересекающиеся коды ошибок, ошибка на одном слое отменяет обработку на всех последующих). Если принять эти принципы, то код 401 для рефреша токена становится логичным, очевидным, удобным.
Абсолютно корректно. Что истекший токен, что невалидный (при попытке брутфорса, например), что вообще отсутствующий суть одна — клиент не аутенфицирован (не подтвердил свою личность), сервер не может определить кто является клиентом, а значит не может определить авторизирован (имеет права) он на запрашиваемое действие с ресурсом, или нет.
Про нумерацию кодов ошибок я, всё-таки, слегка преувеличил. Схема уж очень нелинейная: http://i.stack.imgur.com/whhD1.png
401 — я не могу тебя узнать (авторизовать, креденшелы невалидны, либо отсутствуют), для доступа к ресурсу я должен знать кто ты.
403 — я тебя узнал (авторизовал), но у тебя чувак нет доступа к этому ресурсу.

В некоторых случаях 403 можно заменить на 404 статус код. Это выгодно когда клиент даже знать не должен о том что есть что-то к чему у него нет доступа. Но это уже отдельные юзкейсы.
Зависит от способа реализации авторизации. Хотя, скорее, вы про аутентификацию :)
Да, вы правы, имелась в виду аутентификация.
А, то есть самодостаточность из пункта 3 — это полнота на уровне протокола, а не на уровне получаемого пользователем документа?
Нет, документ, например, html или json, должен быть синтаксически полным. Но при этом имеет право ссылаться на другие документы.
Исходя из статьи делаю вывод, что GET по адресу для создания новой сущности на сервере и получение в ответе 200 {status: 404, message: 'No ok'} есть верный RESTful?
Что б уж совсем был RESTful, для создания сущности лучше все же POST.
Я о том, что очень важные условия RESTful в статье не упомянули.
В самом начале статьи написано: «RESTful это не про HTTP, это вообще не про протоколы интернета. ». далее эта мысль развёртывается. таким образом ваш случай RESTful но не http REST
Интересный вывод. Будет о чем похоливарить на работе )
В оригинальной диссертации, если я правильно понял о чём это, написано:

5.3.2 Connector View
REST does not restrict communication to a particular protocol,… but the architecture also includes seamless access to resources that originate on pre-existing network servers, including FTP...
Это семантически неверная реализация RESTful над HTTP :) Ну и с некоторым http-ориентированным сетевым софтом типа браузеров или прокси могут быть проблемы,
Хорошо бы инфу именно в направлении RESTful над HTTP, так как не встречал еще RESTful не над HTTP.
Об этом много инфы (хотя зачастую противоречивой в деталях), тут именно описание что такое RESTful в принципе.
Таки наоборот, подобную данной статье инфу я уже несколько раз находил (даже на хабре), а вот подробного и непротиворичивого описания RESTful на HTTP еще нет )
А его и не будет, потому что RESTful — лишь принципы построения архитектуры распределенных систем, из них не вытекает одна единственная реализация на HTTP.
UFO just landed and posted this here
В вашем примере попробуйте осуществить обратное действие (GET или DELETE), тогда станет ясно, как это должно выглядеть.
А это вы решаете как организовать свои ресурсы. Например при REST над HTTP вы можете решить, что пост с комментариями один ресурс и добавлять комментарии с помощью метода PATCH, а можете решить, что комментарии отдельные ресурсы и добавлять их при помощи метода POST, ссылаясь на пост.
UFO just landed and posted this here
Путаница обычно из-за других вещей, типа той же аутентификации.
UFO just landed and posted this here
Например, как в рамках рестфул реализовать привычную сессионную аутентификацию, когда клиент один раз отправляет аутентификационную информацию, получает сессиионную кук, а потом пользуется ею пока сам не разлогинится или сервер его не разлогинит.
UFO just landed and posted this here
В том, что такая реализация перестаёт быть stateless.
UFO just landed and posted this here
Есть. Клиент делает запрос, указывая полученную от сервера куку, предполагая, что на сервере есть сессия с таким идентификтором. Сервер отклоняет запрос, если предположение клиента неверно.
UFO just landed and posted this here
Серверу нужно знать историю запросов клиента — отправлял он верные аутентификационные данные за последнее время или нет.
зачем? т.е. мне интересно узнать что вы имеете в виду под этим, ну и зачем конкретно
Обычный сценарий:
— клиент отправляет на /login имя и пароль
— сервер создаёт сессию
— сервер проверяет валидность имени и пароля
— если всё хорошо, записывает в сессию признак, что клиент аутентифицировался
— отправляет клиенту результат и сессионную куку
— клиент в следующем значимом запросе отправляет эту куку
— сервер поднимает сессию по куке и проверяет есть ли в ней признак аутентификации, то есть отправлял ли клиент валидные аутентификационные данные
— если всё ок, то запрос выполняется
UFO just landed and posted this here
Поддерживаю, начал тоже было в том комменте писать про комментарии и статьи, но решил уточнить что конкретно имеется в виду.

VolCh на токенах ситуация примерно аналогичная

— на метод логина отправляем данные (по сути это не логин, а создание нового токена, POST /tokens, если удобно).
— проверяем логин-пароль, если все ок — отдаем сущность нового токена, которым затем подписываем каждый запрос.
— при последующих запросах просто проверяем наличие переданного в запросе токена где-либо и достаем из токена идентификатор пользователя — это не ломает stateless, токен такая же сущность, что и статья и другие, и если они не найдены — возвращаем ошибку, либо работаем с ними, если все ок.
— чтобы сделать логаут — DELETE /tokens/{token}
Непонятно, чем такое поведение принципиально отличается от установление TLS сессии (где в качестве токена выступает полученный secret) или http2, где есть состояние на клиенте и сервере, которые могут быть в любой момент сброшены, т. к. предназначены они для оптимизации.

Или, может, стоит запретить использование HTTP/1.1? Там же есть keep-alive…
Проблема такая: по REST вы шлете только и только запрос только и только его. До этого про Вас сервер «НИЧЕГО» не слышал. И на основании запроса он говорит либо результат либо «Приходи вчера», т.е. ошибку.
Если же Вы будете использовать обычную сессионную аутентификацию, к примеру http auth digest, то это ошибка архитектуры! Это не по REST! Т.к. требуется предварительный handshake, а в REST такого нету! В REST «без запоминания состояния».

Еще раз: В запросе должно быть ВСЕ чтобы выполнить его или сказать об ошибке.

Единственный handshake между клиентом и сервером это может быть на уровне TCP-протокола и только.

Именно поэтому многие реализуют запросы в виде тело + N-минутный токен. на основании этого можно получить либо ошибку либо результат
Единственный handshake между клиентом и сервером это может быть на уровне TCP-протокола и только.
Т. е. вы отрицаете допустимость использования TLS или, скажем, HTTP2?
Это не stateless протоколы в общем случае. Нельзя построить REST на их основе. Можно поверх них построить прикладной протокол, используя их в качестве сеансового уровня, но обычно под REST HTTP понимают всё же REST как подмножество HTTP.
Это не stateless протоколы в общем случае.
Я это и имею ввиду. Как и TCP, если уж на то пошло. Или использование аутентификации и bearer token после (stateful для клиента, как минимум). Или использование Set-Cookie. Нет почти ничего stateless в реальном мире.

REST, как подмножество HTTP звучит тоже довольно странно, т. к. в RESTful любят всякие PUT/DELETE/PATCH, которые могут не поддерживаться по дороге. А PATCH вообще не содержит целостного представления обновляемого ресурса.
Выше же был ответ на этот вопрос — токены в каждом запросе
Где брать токены простой html-форме?
Так в смысле, простой html-форме? Тогда я не особо понимаю о чем вы.

Если вы про то, что вернувшийся с сервера токен html-форма никак не подхватит, то насколько я помню, нигде ведь не говорится, что restful подход реализуется средствами простых html-форм, поэтому либо прибегаем к каким-то дополнительным инструментам, помимо чистого html, либо как-то извращаемся и немного ломаем понятия.

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

Поэтому, если отбросить все нюансы кук (все, в том числе описанные в диссере Филдинга), взять необходимость реализации аутентификации на чистых формах, то при большом желании сервер при логине может установить куку с тем самым токеном, а клиент их будет отправлять обратно, то есть каких-то принципиальных отличий между токеном в заголовке и кукой в таком исключительном случае я, по крайней мере, не вижу, потому как все состояние как таковое хранится на клиенте.
HTTP в целом stateless протокол, предусматривающий в том числе и аутентификацию несколькими способами, но в силу ряда причин эти способы мало используются, особенно на серверах, где основной текстовый контент отдаётся в html, а основные клиенты — браузеры.

В том же OAuth есть два сервера: сервер ресурсов и сервер аутентификации. Токен выдаёт сервер аутентификации, процесс его выдачи не входит в логику работы сервера ресурсов, последний ожидает токен в каждом запросе, для него токен — аутентифицирующая информация типа логина и пароля. С классическими же формами такое разделение плохо работает.
Так проблема же не в классических формах, а в том, что из них пытаются сделать клиентскую оболочку для restful
Проблема в том, прежде всего, что где-то в 90-х, емнип, стало популярно использовать сессии на стороне сервера для, прежде всего, аутентификации и авторизации. Один раз отправили пароль, получили куку, а по ней на сервере сессия с, как минимум, идентификатором пользователя.
Так популярно и пусть.
Это же не отменяет того, что я написал выше — нет смысла делать что-то, из чего это сделать напрямую нельзя.
Путаница — может быть, я уже понял это исходя из диалога. Проблема — пока не вижу её из того, что вы пишете относительно «как в рамках рестфул реализовать привычную сессионную аутентификацию, когда клиент один раз отправляет..»
Нет никаких внятных правил о том, как будет выглядеть то, что вы ещё не спроектировали. Проектирование — отдельная работа (идущая перед реализацией), которую никакой справочник паттернов не заменит. Увы, в программировании необходимо понимать то, что делаешь.
www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_2_1_1

www.restapitutorial.com/lessons/restfulresourcenaming.html

Ну а вообще, если всё перевести в плоскость коллекций, то становится проще в этом плане. И добавление комментария к посту становится добавлением комментария к списку комментариев, который имеет ссылку на пост.
К сожалению REST это больше buzzword и в лучше случае список рекомендаций, чем реальная база для разработки API на HTTP.

Да и статью следовало бы назвать «Определение REST от Рой Филдинга (автора термина)».
Для удовлетворения принципов этого «баззворда» разработали HTTP. Не стОит называть всё то, что абстрактнее вашего уровня восприятия, баззвордами. REST — это не религия, не магия, это развитые принципы обеспечения масштабируемости (и на вычислительные ресурсы, и на количество пользователей) инфо-систем, родившиеся из конкретных реальных проблем и конкретных изначально частных их решений. HTTP — это прикладной протокол, а не транспортный.
Для удовлетворения принципов этого «баззворда» разработали HTTP.
WAT? Что вы хотели этим сказать?

Во-первых, HTTP — не REST. Или вы может быть скажете, что такие вещи как Cookie и Keep-Alive полностью соответствуют REST?

Во-вторых, вы уверены, что HTTP именно под принципы REST разрабатывали? Особенно с учетом огромной разницы в годах появления?

В-тертьих, у конкретно REST есть все основные признкаи «buzzword»: 1) есть много-много разных определений, 2) соответствут система условиям REST в каждом конкретном случае или нет является свпорным вопросм, 3) термин (не решение!) продвигается на лево и направо.
Да, термин REST появился позже создания протокола HTTP, как результат переосмысления того, каким сложились его текущие реализации, каковы проблемы и каким он должен получиться в итоге. Ваше недоумение относительно хронографии возникновения терминов правомерно.
Для удовлетворения принципов этого «баззворда» разработали HTTP
Кстати, да — Рой Филдинг является не только автором концепции REST, но и одним из авторов спецификации HTTP (по крайней мере с версии 1.0, где были только GET, POST и HEAD) и одним из основателей проекта Apache.
>Каждый ресурс должен быть уникально обозначен постоянным идентификатором

Я выбираю запросом список строк, которые удовлетворяют какому-то требованию. Что тут будет идентификатором ресурса? Ресурс — это список строк. При следующем запросе этот список будет другой, даже если требования будут те же. В чём смысл идентификатора такого ресурса, как его можно использовать, и как его реализовать?
В вашем случае ресурс динамический, меняется не один ресурс на другой, а состояние одного и того же ресурса. Это не конкретное фиксированное множество строк, а множество, удовлетворяющее ваш запрос на текущий момент времени. Представьте URL, по которому сервер возвращает текущее время. То, что при каждом запросе будет приходить новое время, не значит, что вы будете получать разные ресурсы. Вы всё так же будете получать запрашиваемый ресурс — текущее время. В вашем случае (в случае http) идентификатором ресурса будет URL вместе с вашими требованиями. Допустим `http://example.com/users?city=moscow`. Требование к постоянству идентификатора говорит о том, что вы не можете просто взять и поменять например имя параметра city на place, не оставив по прежнему адресу информации о новом размещении ресурса, и не можете поменять смысл параметра (например, вместо пользователей из Москвы начать показывать пользователей, у которых Москва — любимый город).
А если требования сложные, передаются в POST — то что будет идентификатором?
URL будет примерно такой: http://example.com/users_by_query
передаются в POST

То это не REST. Выбор между GET и POST осуществляется не на основе количества параметров, а на основе семантики запроса. Вы же сами почти полное предложение по-английски написали: «GET users_by_query».
А как в рамках REST описывать такие запросы, которые получают много параметров и возвращают какой-то ресурс?
Также, как запросы, которые получают мало параметров или не получают вообще. «GET users_by_query?filter=123» — вполне нормальный вариант.
А 100 килобайт параметров как передать?
СтОит попробовать пересмотреть архитектуру вашей информационной системы. Возможно то, что вы называете параметрами, является данными (другими ресурсами).
Прежде чем приступить к реализации подобного решения с множеством параметров спросите себя, а кто будет пользователем вашего API. Если человек, то это лучше всего сделать через URI, если же машина, то ей пофиг, но программировать удобнее через мини-URI и остальное в теле запроса
например, ввести сущность userfilter («фильтр по пользователям»), создать экземпляр этой сущности, получить ее id и отдать отфильтрованных пользователей по GET /userfilter/{id}/users
Зачем? Вы фильтруете список пользователей, так и применяйте к нему фильтр, а не к фильтру передавайте список.

GET /users?filter=some-filter-name-or-id
я, конечно, допускаю, что я ошибаюсь, но, по-моему, в RESTful HTTP нет операции применения чего либо к чему-либо, как это характерно для RPC. Я именно беру объект фильтр в идентификатором id и беру у него дочернюю коллекцию users. Я имею право так делать, т.к. я именно так определил entity userfilter. И у меня есть только операции получения entity и списка entity, но никаких операций применения чего-либо у чему-либо
Повторюсь, что я имел в виду только лишь само название итогового URI и его интерпретацию с точки зрения разработки, ни о каком явном применении речи не шло. Так как ну по сути своей, разницы между /users?filter={some-filter-name-or-id} и GET /userfilter/{id}/users нет никакой.

Но мне в любом случае непонятна такая логика, когда у фильтра что-то есть дочернее. Может, у нас разные понятия фильтров или я чего-то не знаю из реализации проекта.
Более разумным выглядит GET /users/filter/{id}
С чего более разумным? Более разумным будет, если после коллекции будет идти идентификатор сущности из этой коллекции, а не совершенно левая по отношению к этому списку сущность или их коллекция.
Не совершенно левая, а связанная отношением многие-к-одному с коллекцией
Это крайне плохой вариант. Конечно, если фильтрация выполняется долго, только так и можно поступать. Но если есть возможность за один запрос получить требуемое, такие нагромождения вредны. К тому же это близко к нарушению принципа «Отсутствие состояния».
Кроме того, GET имеет свойство idempotent'ности, а вызов ещё раз того же «GET /users?filter=some-filter-name-or-id » возвратит не тот же результат.
Эмм?
Вас почти ничего не спасет от изменения списка при фильтрации пользователей, на то он и список, чтобы изменяться и идемпотентность GET тут не причем, тем более что идемпотентность имеет несколько другой смысл (отсутствие любых сайд-эффектов), а не просто «сделал запрос и получил всегда абсолютно идентичный предыдущему запросу ответ».
Под почти ничего имею в виду использование в запросе временных границ, которые каким-либо образом ограничивают выборку новых записей. Старые записи, конечно же, могут пропасть.

Да и каким образом это близко к нарушению stateless?
stateless — мы ведь должны первым запросом создать на сервере ресурс (фильтр), и второй запрос подразумевает, что выполнен первый. То есть сервер приобретает свойство иметь состояние. (сервер или клиент — мне кажется, в данном случае состояние именно у сервера).

Насчёт идемпотентности я согласен. Остаётся первый вопрос — два запроса вместо одного.

На свой исходный вопрос я получил, наверно, ответ в https://cloud.google.com/bigquery/docs/reference/v2/jobs/query.
Я понял про что вы, но состояния здесь нет. Это аналогично примеру выше, с постом и комментами.

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

Нет разницы между успешным созданием поста и отправкой на него комментария через секунду и отправкой комментария через год — что в первом, что во втором случае между созданием поста и отправкой комментария не возникнет состояния, это будет 2 (с постом 3) абсолютно независимых запроса.
Но всё же разумно ли делать два запроса вместо одного? Пример https://cloud.google.com/bigquery/docs/reference/v2/jobs/query работает так: если ответ на запрос (POST) есть — возвращает его, если ещё нет (за заданное время) — возвращает идентификатор задания (то есть фильтр). На самом деле всегда возвращает ресурс, часть которого и ответ, и идентификатор. Получается, что именно то что я в первом посте написал и выполняется. Правильно ли гугл построил это запрос в рамках REST?
Где конкретно два запроса, с юзерфильтрами? why not? Мое замечание было лишь по поводу того, что название ресурса было не совсем логичным.

Если система создана с условием, что пользователи системы могут создавать пользовательские фильтры и сохранять их, например, какая-нибудь там финансовая система с фильтром финансовых показателей по куче полей — решили прикрутить фичу «сохранить фильтр под названием», то пусть, никто не запрещает. Только тогда логика должна быть такая, что есть несколько ресурсов — фильтры и список финансовых показателей, т.е. какие-нибудь там /filters и /finance-results

Делаете POST на /filters с теми полями, которые вам разрешил сервер, получаете например имя фильтра или его id в случае успешного создания или 400 ошибку в случае плохого. Впоследствии, фильтр можно будет изменить по запросу PUT/PATCH /filters/{filter-id-or-name}. И там уже снова, либо шибки валидации, либо 404, в случае, когда фильтр с таким названием или идентификатором не найден.

Затем варианта два с половиной:
— Либо делаем просто GET /finance-results и получаем например первые 10 записей сверху
— Либо делаем запрос типа GET /finance-results?filter={filter-id-or-name}, который уже применяет фильтр, указанный пользователем в запросе.
— Если же вдруг по каким-то причинам фильтра не существует, или клиент указал неправильное название фильтра — там уже на усмотрение тех, кто создает систему, но я бы вернул либо пустой список, либо ошибку, что фильтра не существует, вот и все.

Если же вопрос про два запроса был про гугл… Не знаком с Google BigQuery, но в таком сценарии, как вы описываете, ничего плохо я, опять же, не вижу.

Формально, в данном случае, вы создаете сущность Job с неким query и возвращает он вам также Job (только в случае успешной валидации), только по мере обработки этой сущности, Job либо заполнен остальными полями (результат выполнения Query), либо нет. Если же создание Job не прошло валидацию, состояния никакого здесь нет — просто вернул список ошибок и все, клиент при этом может делать все что угодно, но логичным действием, конечно же, будет новый запрос на создание Job с исправлениями (а не запрос на какой-нибудь адрес проверки статуса Job, который не создан), и гугл снова его независимо от других запросов на создание его провалидирует.

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

Всё просто — получил, выполнил, вернул.
А если кто-то изменит userfilter между генерацией и вторым запросом?
ровно та же ситуация, как кто-то добавит пост к блогу до того, как вы сами добавили первый пост и, к вашему удивлению, список постов окажется не пуст, хотя вы этого не ожидали. Защита в обоих случаях может быть предложена одинаковая — разрешение изменения только создателем. Для разрешения конфликтов конкурентных изменений создателем (например из соседних вкладок) протокол допускает передачу версии объекта.
Вапще вопросы про HTTP REST возникают из-за смешения уровней проектирования. RESTful-интерфейс может быть реализован и над HTTP, и над протоколом уровнем выше, и над протоколом уровнем выше.

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

С точки зрения архитектуры, перед RESTful-сервером стоит, как минимум, HTTP-сервер, а чаще ещё и интерпретатор скриптов. То есть, HTTP запросы, передаваемые HTTP-серверу не обязаны быть RESTful, они обязаны стать RESTful во время перехода вверх по архитектуре.

Например, HTTP-сервер может получать только GET и POST, но он может симулировать другие методы с помощью дополнительного параметра или заголовка. Но HTTP-сервер обязан передать выше запрос, преобразованный таким образом, чтобы применяемый метод передавался единообразно. То есть, каким бы способом мы не указали желаемый метод для HTTP-сервера, он или использует исходный, или возьмёт замещаемый метод из заголовка, или возьмёт его из параметра запроса. В этот момент, HTTP-сервер нарушит принципы RESTful, но ведь он и не обязан их соблюдать. Зато, стоящий дальше RESTful сервер получит полный и единообразный запрос, который соответствует принципам RESTful.

Ещё пример, клиент в ходе работы использует некие защищённые данные сеанса. С точки зрения RESTful мы не можем сохранять состояние. Однако, мы можем построить архитектуру таким образом, чтобы RESTful-компонентам и не приходилось это делать. Например, таким образом: клиент отправляет HTTP-серверу запрос с идентификатором сеанса. HTTP-сервер получает данные сеанса из хранилища (файла, базы, памяти… не важно) и присоединяет их к запросу, который получает RESTful-сервер. С точки зрения RESTful-сервера некий клиент прислал ему полный запрос, не требующий дополнительной обработки, который можно просто выполнить, ведь данные полны, и их достаточно. В ответ мы отправляем клиенту и результат, и изменённые пользовательские данные сеанса. При окончательной отправке клиенту данные сеанса HTTP-сервер сохраняет в хранилище и заменяет идентификатором. С точки зрения RESTful-сервера мы ничего не нарушили.

HTTP-сервер и RESTful-сервер здесь — скорее логические, чем фактические понятия. Они могут быть реализованы в рамках одного исполняемого компонента. Но могут быть и фактически двумя разными программными и даже аппаратными серверами. Протокол их общения друг с другом тоже произвольный. В рамках одного компонента это может быть и вовсе простой вызов функций, где запрос представляется в виде структуры в памяти. Точно так же можно разделить RESTful-клиент и HTTP-клиент.

Вапще, ещё начиная с модели OSI вся сеть представляет из себя конвейер, или, скорее, матрёшку. Когда кто-то бунтует по поводу того, зачем ему знать OSI, я отвечаю — это основа, показывающая, как проектировать сетевые приложения. Главный принцип — если что-то не реализуется на одном уровне, реализуй уровень выше, сделай матрёшку поменьше, чтобы вложить в исходную. Так и с RESTful, его ограничения достаточно строги для реализации на уровне HTTP, но никто не запрещает сделать уровень над HTTP, и реализовать его по принципу RESTful.
Уже давно вижу статьи, «срывающие покровы с RESTful».

Считаю, что на RESTful как и на паттернах проектирования не нужно зацикливаться. Руководствуйтесь здравым смыслом. API должен быть прост, понятен и удобен для пользователя. Это гораздо важнее строгого соответствия какой бы то ни было парадигме.
Попытка соответствия какой-либо парадигме без понимания принципов этой парадигмы и решаемых ею проблем — культ Карго. «Руководствуйтесь здравым смыслом» = «пользуйтесь методами и инструментами, в которых компетентны, выделяйте отдельное время для освоения новых подходов прежде чем применять их в рабочих проектах.»
Sign up to leave a comment.