Имейте в виду, что у меня есть элементарное понимание REST. Допустим, у меня есть этот URL:
http://api.animals.com/v1/dogs/1/
А теперь я хочу, чтобы сервер заставлял собаку лаять. Только сервер знает, как это сделать. Допустим, я хочу, чтобы он выполнял задание CRON, которое заставляет собаку лаять каждые 10 минут до конца вечности. Как выглядит этот звонок? Я как бы хочу это сделать:
URL-запрос:
ACTION http://api.animals.com/v1/dogs/1/
В теле запроса:
{"action":"bark"}
Прежде чем вы рассердитесь на меня за создание моего собственного HTTP-метода, помогите мне и дайте мне лучшее представление о том, как мне вызывать серверный метод в RESTful-стиле. :)
РЕДАКТИРОВАТЬ ДЛЯ УТОЧНЕНИЯ
Еще несколько пояснений по поводу того, что делает метод «коры». Вот несколько вариантов, которые могут привести к вызовам API с другой структурой:
- bark просто отправляет электронное письмо на dog.email и ничего не записывает.
- bark отправляет электронное письмо на адрес dog.email, и значение dog.barkCount увеличивается на 1.
- bark создает новую запись "лая" с записью bark.timestamp, когда возник лай. Он также увеличивает dog.barkCount на 1.
- bark запускает системную команду для получения последней версии кода собаки с Github. Затем он отправляет сообщение dog.owner о том, что новый код собаки находится в разработке.
api
rest
url
api-design
restful-architecture
Кирк Уимет
источник
источник
PATCH
может подойти . Я объясняю почему ближе к концу своего ответа .Ответы:
Зачем стремиться к дизайну RESTful?
Принципы RESTful привносят функции, которые упрощают работу с веб-сайтами (для случайного пользователя, который может «просматривать» их), в дизайн API веб-сервисов , поэтому программист может легко ими пользоваться. REST хорош не потому, что это REST, а потому, что он хорош. И в основном это хорошо, потому что это просто .
Простота обычного HTTP (без SOAP-конвертов и перегруженных
POST
сервисов с одним URI ), что некоторые могут назвать «отсутствием функций» , на самом деле является его самой сильной стороной . HTTP сразу же требует адресуемости и отсутствия состояния : двух основных проектных решений, которые сохраняют масштабируемость HTTP до сегодняшних мегасайтов (и мегасервисов).Но REST - не лучшая идея: иногда может быть уместен стиль RPC («Удаленный вызов процедур» - например, SOAP) , а иногда другие потребности имеют приоритет над достоинствами Интернета. Это отлично. Что нам не очень нравится, так это ненужная сложность . Слишком часто программист или компания прибегают к услугам в стиле RPC для работы, с которой простой старый HTTP справился бы отлично. В результате HTTP сокращается до транспортного протокола для огромной полезной нагрузки XML, который объясняет, что «на самом деле» происходит (не URI или метод HTTP дают подсказку об этом). Полученная в результате услуга слишком сложна, ее невозможно отладить и она не будет работать, если ваши клиенты не настроят точную настройку, как задумал разработчик.
Точно так же код Java / C # может быть не объектно-ориентированным, простое использование HTTP не делает дизайн RESTful. Кто-то может быть захвачен стремлением думать об их сервисах с точки зрения действий и удаленных методов, которые следует вызывать. Неудивительно, что это в основном заканчивается службой в стиле RPC (или гибридом REST-RPC). Первый шаг - думать иначе. RESTful-дизайн может быть реализован разными способами, один из них - думать о своем приложении с точки зрения ресурсов, а не действий:
Я приведу примеры ниже. (Другой ключевой аспект REST - это использование HATEOAS - я не прикрашиваю его здесь, но я быстро расскажу об этом в другом посте .)
Проблемы первого дизайна
Посмотрим на предлагаемую конструкцию:
Во-первых, нам не следует рассматривать создание новой HTTP-команды (
ACTION
). Вообще говоря, это нежелательно по нескольким причинам:ACTION
существовании глагола?Теперь давайте рассмотрим использование
POST
(я расскажу, почему ниже, просто поверьте мне сейчас на слово):Это могло быть нормально ... но только если :
{"action":"bark"}
был документ; а также/v1/dogs/1/
был URI-адресом "обработчика документов" (фабричным). «Обработчик документов» - это URI, в который вы просто «бросаете вещи» и «забываете» о них - процессор может перенаправить вас на вновь созданный ресурс после «выброса». Например, URI для отправки сообщений в службу брокера сообщений, которая после публикации перенаправит вас на URI, который показывает статус обработки сообщения.Я мало что знаю о вашей системе, но готов поспорить, что оба утверждения неверны:
{"action":"bark"}
это не документ , это фактически метод, которым вы пытаетесь проникнуть в сервис; а также/v1/dogs/1/
URI представляет собой «собака» ресурс (вероятно, собака сid==1
) , а не документ процессора.Итак, все, что мы знаем сейчас, - это то, что приведенный выше дизайн не такой уж RESTful, но что это именно? Что в этом плохого? По сути, это плохо, потому что это сложный URI со сложным значением. Вы ничего не можете сделать из этого. Откуда программисту знать, что у собаки есть
bark
действие, которое можно тайно вложитьPOST
в него?Разработка вызовов API вашего вопроса
Итак, давайте перейдем к делу и попробуем спроектировать этот лай в режиме ОТДЫХА, думая о ресурсах . Позвольте мне процитировать книгу Restful Web Services :
После описания выше , мы можем увидеть , что
bark
может быть смоделированы как в subresource изdog
(так какbark
содержится внутри собаки, то есть кора «окорененная» от собаки).Из этого рассуждения мы уже получили:
POST
/barks
, подресурс dog:,/v1/dogs/1/barks
представляет собойbark
«фабрику». Этот URI уникален для каждой собаки (так как он находится ниже/v1/dogs/{id}
).Теперь каждый случай из вашего списка имеет определенное поведение.
1. bark просто отправляет электронное письмо
dog.email
и ничего не записывает.Во-первых, лай (отправка электронного письма) - это синхронная или асинхронная задача? Во-вторых,
bark
требуется ли для запроса какой-либо документ (может быть, электронная почта) или он пустой?1.1 bark отправляет электронное письмо
dog.email
и ничего не записывает (как синхронная задача)Это простой случай. Обращение к
barks
ресурсу factory сразу же дает лай (отправленное электронное письмо), и сразу же выдается ответ (если все в порядке или нет):Поскольку он ничего не записывает (не меняет), этого
200 OK
достаточно. Это показывает, что все прошло как положено.1.2 bark отправляет электронное письмо
dog.email
и ничего не записывает (как асинхронная задача)В этом случае у клиента должен быть способ отслеживать
bark
задачу. Тогдаbark
задача должна быть ресурсом с собственным URI .:Таким образом, каждый
bark
может быть отслежен. Затем клиент может выдатьGET
вbark
URI , чтобы знать это текущее состояние. Может быть, даже использовать,DELETE
чтобы отменить это.2. bark отправляет электронное письмо на адрес,
dog.email
а затем увеличивает егоdog.barkCount
на 1Это может быть сложнее, если вы хотите сообщить клиенту, что
dog
ресурс был изменен:В этом случае
location
цель заголовка - дать понять клиенту, что он должен взглянуть на негоdog
. Из HTTP RFC о303
:Если задача асинхронная,
bark
подресурс необходим, как и в1.2
ситуации, и303
должен быть возвращен в a,GET .../barks/Y
когда задача будет завершена.3. bark создает новую "
bark
" запись сbark.timestamp
записью, когда "лай" произошел. Он также увеличиваетсяdog.barkCount
на 1.Здесь
bark
создается по запросу, поэтому применяется статус201 Created
.Если создание асинхронно, вместо этого
202 Accepted
требуется ( как указано в HTTP RFC ).Сохраненная метка времени является частью
bark
ресурса и может быть извлечена с помощью элементаGET
. Обновленная собака также может быть «задокументирована»GET dogs/X/barks/Y
.4. bark запускает системную команду для получения последней версии кода собаки с Github. Затем он отправляет текстовое сообщение, чтобы
dog.owner
сообщить им, что новый код собаки находится в разработке.Формулировка этого сложная, но в значительной степени это простая асинхронная задача:
Затем клиент выдаст
GET
s, чтобы/v1/dogs/1/barks/a65h44
узнать текущее состояние (если код был извлечен, электронное письмо было отправлено владельцу и т. Д.). Всякий раз, когда собака меняется, применяется303
a.Подведение итогов
Цитата Роя Филдинга :
В приведенных выше примерах
POST
спроектирован единообразно. Это сделает собака "bark
". Это небезопасно (это означает, что лай оказывает влияние на ресурсы) или идемпотентным (каждый запрос дает новыйbark
), что хорошо соответствуетPOST
глаголу.Программист знал бы: от a
POST
доbarks
abark
. Коды состояния ответа (также с телом объекта и заголовками, если необходимо) объясняют, что изменилось и как клиент может и должен действовать.Примечание. В качестве первичных источников использовались: книга « Restful Web Services », HTTP RFC и блог Роя Филдинга .
Редактировать:
Вопрос и, следовательно, ответ немного изменились с момента их создания. Оригинальный вопрос задан вопрос о дизайне URI , как:
Ниже приводится объяснение того, почему это не лучший выбор:
Как клиенты сообщают серверу, ЧТО ДЕЛАТЬ с данными - это информация о методе .
КАКАЯ ЧАСТЬ данных [клиент хочет, чтобы сервер] оперировал, является информацией об объеме .
В качестве примера возьмем URI Google
http://www.google.com/search?q=DOG
. Там информация о методе и информацияGET
об объеме/search?q=DOG
.Короче говоря:
И практическое правило:
Вы можете поместить «лай» «действие» в URL-адрес (или в тело объекта) и использовать
POST
. Нет проблем, это работает и, возможно, самый простой способ сделать это, но это не RESTful .Чтобы ваш сервис оставался действительно RESTful, вам, возможно, придется сделать шаг назад и подумать о том, что вы действительно хотите здесь сделать (какое влияние это окажет на ресурсы).
Я не могу говорить о ваших конкретных бизнес-потребностях, но позвольте мне привести пример: рассмотрим службу заказов RESTful, где заказы размещаются по URI, например
example.com/order/123
.Теперь предположим, что мы хотим отменить заказ, как мы это сделаем? У кого-то может возникнуть соблазн подумать, что это « действие» «отмены », и спроектировать его как
POST example.com/order/123?do=cancel
.Это не RESTful, как мы говорили выше. Вместо этого мы могли бы
PUT
создать новое представлениеorder
сcanceled
элементом, отправленным по адресуtrue
:Вот и все. Если заказ не может быть отменен, может быть возвращен конкретный код статуса. (Для простоты также может быть доступен дизайн подресурсов, как и в случае
POST /order/123/canceled
с телом объектаtrue
.)В вашем конкретном сценарии вы можете попробовать нечто подобное. Таким образом, когда собака лает, например,
GET
at/v1/dogs/1/
может включать эту информацию (например<barking>true</barking>
) . Или ... если это слишком сложно, ослабьте требования RESTful и придерживайтесь ихPOST
.Обновить:
Я не хочу делать ответ слишком громоздким, но требуется время, чтобы научиться раскрывать алгоритм ( действие ) как набор ресурсов. Вместо того чтобы думать в терминах действий ( «выполнить поиск мест на карте» ), нужно думать в терминах результатов этого действия ( «список мест на карте, соответствующих критериям поиска» ).
Вы можете вернуться к этому шагу, если обнаружите, что ваш дизайн не соответствует единому интерфейсу HTTP.
Переменные запроса представляют собой информацию об области действия , но не обозначают новые ресурсы (
/post?lang=en
очевидно, это тот же ресурс/post?lang=jp
, только другое представление). Скорее, они используются для передачи состояния клиента (например?page=10
, чтобы это состояние не сохранялось на сервере;?lang=en
это также пример здесь) или входных параметров для алгоритмических ресурсов (/search?q=dogs
,/dogs?code=1
). Опять же, не отдельные ресурсы.Свойства HTTP-глаголов (методов):
Еще один четкий момент, который показывает,
?action=something
что URI не является RESTful, - это свойства HTTP-глаголов:GET
иHEAD
безопасны (и идемпотентны);PUT
иDELETE
являются только идемпотентными;POST
ни то, ни другое.Безопасность : запрос
GET
orHEAD
- это запрос на чтение некоторых данных, а не запрос на изменение состояния сервера. Клиент может сделатьGET
илиHEAD
запросить 10 раз, и это то же самое, что сделать это один раз или не сделать вообще .Идемпотентность : идемпотентная операция в одном, которая имеет одинаковый эффект независимо от того, применяете ли вы ее один или более одного раза (в математике умножение на ноль идемпотентно). Если вы
DELETE
используете ресурс один раз, повторное удаление будет иметь тот же эффект (ресурсGONE
уже есть).POST
не является ни безопасным, ни идемпотентным. Выполнение двух идентичныхPOST
запросов к «фабричному» ресурсу, вероятно, приведет к тому, что два подчиненных ресурса будут содержать одинаковую информацию. При перегруженном (метод в URI или теле объекта)POST
все ставки отключены.Оба эти свойства были важны для успеха протокола HTTP (в ненадежных сетях!): Сколько раз вы обновляли (
GET
) страницу, не дожидаясь ее полной загрузки?Создание действия и его размещение в URL-адресе явно нарушает контракт методов HTTP. Еще раз: технология позволяет, вы можете это делать, но это не RESTful-дизайн.
источник
POST
«предоставлением блока данных ... процессу обработки данных», но разница в том, что блок данных , а не блок данных и процедура (действие, метод, команда) должны быть казнен тогда. ЭтоPOST
перегрузка, аPOST
перегрузка - это дизайн в стиле RPC, а не RESTful./bark/
а иногда и/barks/
во фрагменте URI. Например. выPOST
включены,/v1/dogs/1/barks
но.../dogs/1/bark/a65h44
в ответах у вас есть заголовок Location. Ресурс всегда должен быть во множественном числе, верно?Location
его можно использовать202
, просто он не имеет стандартного поведения для этого кода состояния, и поэтому вы должны убедиться, что ответ понятен с использованием других средств, таких как гипертекст, содержащий гиперссылку. Другими словами: стандарт не говорит, чтоLocation
означает для 202, но не запрещает вам использовать его для 202. Если вы его используете, вы должны объяснить пользователю, что это означает. Я попытался указать на это в ответе ...Я отвечал ранее , но этот ответ противоречит моему старому ответу и следует другой стратегии для поиска решения. Он показывает, как HTTP-запрос построен на основе концепций, определяющих REST и HTTP. Он также использует
PATCH
вместоPOST
илиPUT
.Он проходит через ограничения REST, затем компоненты HTTP, а затем - возможное решение.
ОТДЫХ
REST - это набор ограничений, предназначенных для применения к распределенной гипермедийной системе, чтобы сделать ее масштабируемой. Даже чтобы понять это в контексте удаленного управления действием, вы должны думать об удаленном управлении действием как части распределенной гипермедийной системы - части системы для обнаружения, просмотра и изменения взаимосвязанной информации. Если это больше проблем, чем оно того стоит, то, вероятно, не стоит пытаться сделать его RESTful. Если вам просто нужен графический интерфейс типа «панель управления» на клиенте, который может запускать действия на сервере через порт 80, тогда вам, вероятно, понадобится простой интерфейс RPC, такой как JSON-RPC, через HTTP-запросы / ответы или WebSocket.
Но REST - это увлекательный способ мышления, и пример в вопросе легко смоделировать с помощью интерфейса RESTful, поэтому давайте возьмемся за эту задачу для развлечения и для обучения.
REST определяется четырьмя ограничениями интерфейса:
Вы спрашиваете, как можно определить интерфейс, удовлетворяющий этим ограничениям, с помощью которого один компьютер приказывает другому компьютеру заставить лаять собаку. В частности, вы хотите, чтобы ваш интерфейс был HTTP, и вы не хотите отказываться от функций, которые делают HTTP RESTful при использовании по назначению.
Начнем с первого ограничения: идентификация ресурса .
Итак, собака - это ресурс. Это нужно идентифицировать.
Вы моделируете собаку, беря набор идентификаторов и представлений и говоря, что все они связаны друг с другом в данный момент. А пока воспользуемся идентификатором «собака №1». Это подводит нас ко второму и третьему ограничениям: представлению ресурсов и самоописанию .
Ниже приводится последовательность байтов, фиксирующих предполагаемое состояние собаки, то есть представление, которое мы хотим связать с идентификатором «собака №1» (обратите внимание, что он представляет только часть состояния, так как не учитывает имя собаки, здоровье , или даже прошлый лай):
Он должен быть прикреплен к метаданным, описывающим его. Эти метаданные могут быть полезны:
Наконец, давайте посмотрим на четвертое ограничение: HATEOAS .
В интерфейсе RESTful клиент получает представление ресурса, чтобы выяснить, как он должен получить или отправить представление. Где-то в приложении должно быть представление, из которого клиент может выяснить, как получать или отправлять все представления, которые он должен иметь возможность получать или отправлять, даже если он следует цепочке представлений для получения этой информации. Это кажется достаточно простым:
Клиент запрашивает представление ресурса, определенного как домашняя страница; в ответ он получает представление, содержащее идентификатор каждой собаки, которую может пожелать клиент. Клиент извлекает из него идентификатор и спрашивает службу, как она может взаимодействовать с идентифицированной собакой, и служба сообщает, что клиент может отправить заявление на английском языке, описывающее часть предполагаемого состояния собаки. Затем клиент отправляет такое заявление и получает сообщение об успехе или сообщение об ошибке.
HTTP
HTTP реализует ограничения REST следующим образом:
идентификация ресурса: URI
представление ресурса : объект-тело
самоописание : метод или код состояния, заголовки и, возможно, части тела объекта (например, URI схемы XML)
HATEOAS : гиперссылки
Вы выбрали
http://api.animals.com/v1/dogs/1
URI. Предположим, клиент получил это с какой-то страницы сайта.Давайте воспользуемся этим телом объекта (значение
next
- метка времени; значение0
означает «когда этот запрос получен»):Теперь нам нужен метод. PATCH соответствует описанию "части предполагаемого состояния", которое мы выбрали:
И несколько заголовков:
Чтобы указать язык тела объекта:
Content-Type: application/json
Чтобы убедиться, что это происходит только один раз:
If-Unmodified-Since: <date/time this was first sent>
И у нас есть просьба:
В случае успеха клиент должен получить
204
в ответ код состояния или,205
если представление/v1/dogs/1/
изменилось, чтобы отразить новый график лая.В случае сбоя он должен получить сообщение
403
и полезное сообщение, почему.Для REST необязательно, чтобы служба отражала расписание лая в представлении в ответ на него
GET /v1/dogs/1/
, но было бы лучше, если бы представление JSON включало это:Рассматривайте задание cron как деталь реализации, которую сервер скрывает от интерфейса. В этом прелесть универсального интерфейса. Клиенту не нужно знать, что сервер делает за кулисами; все, что его волнует, - это то, что служба понимает запрошенные изменения состояния и реагирует на них.
источник
Большинство людей используют для этого POST . Он подходит для выполнения «любой небезопасной или неидемпотентной операции, когда никакой другой метод HTTP не кажется подходящим».
API, такие как XMLRPC, используют POST для запуска действий, которые могут запускать произвольный код. «Действие» включается в данные POST:
Пример RPC приведен, чтобы показать, что POST - это обычный выбор HTTP-глаголов для серверных методов. Вот мысли Роя Филдинга о POST - он в значительной степени говорит, что RESTful использовать указанные методы HTTP.
Обратите внимание, что сам по себе RPC не очень RESTful, потому что он не ориентирован на ресурсы. Но если вам нужно безгражданство, кеширование или многоуровневость, нетрудно выполнить соответствующие преобразования. См. Пример на http://blog.perfectapi.com/2012/opinionated-rpc-apis-vs-restful-apis/ .
источник
POST api.animals.com/v1/dogs1?action=bark
/RPC2
ничего не делает для идентификации ресурса - он определяет серверную технологию. Вместо этого онmethodName
пытается «идентифицировать» «ресурс» - но даже в этом случае он не выигрывает от различия существительного и глагола; единственная вещь, похожая на глаголmethodCall
. Это похоже на «выполнить поиск имени-состояния» вместо «получить имя-состояния» - последнее имеет гораздо больший смысл.POST
это метод HTTP, разработанный дляМетоды на стороне сервера, обрабатывающие действия, не связанные с CRUD, - это то, что Рой Филдинг намеревался использовать с REST, так что вы хороши в этом, и поэтому
POST
были сделаны неидемпотентными.POST
будет обрабатывать большую часть отправки данных в методы на стороне сервера для обработки информации.Тем не менее, в вашем сценарии собачьего лая, если вы хотите, чтобы лай на стороне сервера выполнялся каждые 10 минут, но по какой-то причине вам нужен триггер, исходящий от клиента, это
PUT
будет лучше служить этой цели из-за его идемпотентности. Что ж, строго по этому сценарию нет очевидного риска того, что несколько запросов POST заставят вашу собаку мяукать, но в любом случае это цель двух похожих методов. Мой ответ на аналогичный вопрос SO может быть вам полезен.источник
PUT
URL-адрес относился к тому, что должно быть заменено содержимым клиента, аPOST
URL-адрес ссылался на то, что должно обрабатывать контент клиента, как он хочет.Если мы предположим, что Лай является внутренним / зависимым / вспомогательным ресурсом, на который может действовать потребитель, то мы могли бы сказать:
собака номер 1 лает
возвращает метку времени последнего лая
не применяется! так что игнорируйте это.
источник
/v1/dogs/1/bark
его как ресурс как таковой иPOST
как описание того, как должно измениться внутреннее состояние этого ресурса. Я считаю, что имеет смысл просто рассматривать/v1/dogs/1/
как ресурс и указывать в теле объекта, что он должен лаять.В более ранних версиях некоторых ответов предлагалось использовать RPC. Вам не нужно смотреть на RPC , поскольку это является вполне возможно делать то , что вы хотите , в то время как придерживаясь ограничений REST.
Во-первых, не указывайте параметры действия в URL-адресе. URL-адрес определяет, к чему вы применяете действие, а параметры запроса являются частью URL-адреса. Его следует рассматривать исключительно как существительное.
http://api.animals.com/v1/dogs/1/?action=bark
это другой ресурс - другое существительное - кhttp://api.animals.com/v1/dogs/1/
. [nb. Аскер удалил?action=bark
URI из вопроса.] Например, сравнитеhttp://api.animals.com/v1/dogs/?id=1
сhttp://api.animals.com/v1/dogs/?id=2
. Разные ресурсы, различающиеся только строкой запроса. Таким образом, действие вашего запроса, если оно не соответствует непосредственно существующему типу метода без тела (TRACE, OPTIONS, HEAD, GET, DELETE и т. Д.), Должно быть определено в теле запроса.Затем решите, является ли действие " идемпотентным », что означает, что его можно повторить без отрицательного эффекта (см. Следующий абзац для более подробного объяснения). Например, установка значения true может быть повторена, если клиент не уверен в достижении желаемого эффекта. Они отправляют запрос снова, и значение остается верным. Добавление 1 к числу не идемпотентно. Если клиент отправляет команду Add1, не уверен, что она работает, и отправляет ее снова, сервер добавил одну или две? Как только вы это определили, у вас будет больше возможностей выбирать между вашим методом
PUT
иPOST
для него.Идемпотент означает, что запрос может быть повторен без изменения результата. Эти эффекты не включают ведение журнала и другие подобные действия администратора сервера. Используя ваш первый и второй примеры, отправка двух электронных писем одному и тому же человеку действительно приводит к другому состоянию, чем отправка одного электронного письма (у получателя есть два в своем почтовом ящике, которые они могут рассматривать как спам), поэтому я определенно использовал бы для этого POST . Если barkCount в примере 2 предназначен для просмотра пользователем вашего API или влияет на что-то видимое для клиента, то это также то, что сделает запрос неидемпотентным. Если он предназначен только для просмотра вами, он считается ведением журнала сервера и должен игнорироваться при определении идемпотентности.
Наконец, определите, можно ли ожидать немедленного успеха действия, которое вы хотите выполнить. BarkDog - это быстро завершающееся действие. RunMarathon - нет. Если ваше действие медленное, подумайте о том, чтобы вернуть
202 Accepted
, с URL-адресом в теле ответа, чтобы пользователь мог опросить, чтобы узнать, завершено ли действие. В качестве альтернативы, попросите пользователей выполнить POST на URL-адрес списка, например,/marathons-in-progress/
а затем, когда действие будет выполнено, перенаправьте их с URL-/marathons-complete/
адреса текущего идентификатора на URL- адрес.Для конкретных случаев №1 и №2 я бы разместил на сервере очередь, а клиент отправлял бы ей пакеты адресов. Действие будет не SendEmails, а что-то вроде AddToDispatchQueue. Затем сервер может опросить очередь, чтобы узнать, есть ли ожидающие адреса электронной почты, и отправить электронные письма, если они найдены. Затем он обновляет очередь, чтобы указать, что ожидающее действие теперь выполнено. У вас будет другой URI, показывающий клиенту текущее состояние очереди. Чтобы избежать двойной отправки электронных писем, сервер также может вести журнал того, кому он отправил это электронное письмо, и сравнивать каждый адрес с ним, чтобы убедиться, что он никогда не отправляет два на один и тот же адрес, даже если вы отправляете один и тот же список дважды на очередь.
Выбирая URI для чего-либо, старайтесь думать о нем как о результате, а не о действии. Например
google.com/search?q=dogs
показывает результаты поиска по слову «собаки». Поиск необязательно выполнять.Случаи №3 и №4 из вашего списка также не являются идемпотентными действиями. Вы предполагаете, что различные предлагаемые эффекты могут повлиять на дизайн API. Во всех четырех случаях я бы использовал один и тот же API, поскольку все четыре меняют «состояние мира».
источник
См. Мой новый ответ - он противоречит этому и более четко и точно объясняет REST и HTTP.
Вот рекомендация, которая подходит для RESTful, но, безусловно, не единственный вариант. Чтобы начать лаять при получении запроса службой:
token
- произвольное число, которое предотвращает повторные лаи независимо от того, сколько раз отправляется этот запрос.next
указывает время следующего лая; ценность0
означает «как можно скорее».Всякий раз
GET /v1/dogs/1/bark-schedule
, когда вы должны получить что-то вроде этого, где t - время последнего лая, а u - t + 10 минут:{"last": t, "next": u}
Я настоятельно рекомендую вам использовать тот же URL-адрес, чтобы запросить лай, который вы используете, чтобы узнать о текущем состоянии лая собаки. Для REST это не обязательно, но он подчеркивает действие изменения расписания.
Соответствующий код состояния, вероятно, 205 . Я представляю себе клиента, который просматривает текущее расписание
POST
по тому же URL-адресу, чтобы изменить его, и получает от службы указание повторно взглянуть на расписание, чтобы доказать, что оно было изменено.Объяснение
ОТДЫХ
Забудьте на мгновение о HTTP. Важно понимать, что ресурс - это функция, которая принимает время в качестве входных данных и возвращает набор, содержащий идентификаторы и представления . Давайте упростим это до: ресурс - это набор R идентификаторов и представлений; R может изменяться - члены могут быть добавлены, удалены или изменены. (Хотя это плохой, нестабильный дизайн для удаления или изменения идентификаторов.) Мы говорим, что идентификатор, который является элементом R, идентифицирует R , и что представление, которое является элементом R, представляет R .
Скажем, R - собака. Вы случайно идентифицировали R как
/v1/dogs/1
. (Значение/v1/dogs/1
является членом R ). Это только один из многих способов , вы могли бы определить R . Вы также можете идентифицировать R как/v1/dogs/1/x-rays
и как/v1/rufus
.Как вы представляете R ? Может быть, с фотографией. Может быть, с набором рентгеновских снимков. А может с указанием даты и времени, когда Р. в последний раз лаял. Но помните, что все это представления одного и того же ресурса .
/v1/dogs/1/x-rays
- это идентификатор того же ресурса, который представлен ответом на вопрос "когда R последний раз лаял?"HTTP
Множественные представления ресурса не очень полезны, если вы не можете сослаться на тот, который вам нужен. Вот почему HTTP полезен: он позволяет связывать идентификаторы с представлениями. . То есть это способ службы получить URL-адрес и решить, какое представление обслуживать клиенту.
По крайней мере, так
GET
оно и есть.PUT
по сути является инверсиейGET
: выPUT
представляете r в URL-адресе, если хотите, чтобы будущиеGET
запросы к этому URL-адресу возвращали r , с некоторыми возможными переводами, такими как JSON в HTML.POST
- более свободный способ изменения представления. Подумайте о существовании логики отображения и логики модификации, которые дублируют друг друга - обе соответствуют одному и тому же URL-адресу. Запрос POST - это запрос логики модификации для обработки информации и изменения любых представлений (а не только представления, расположенного по тому же URL-адресу), как считает служба. Обратите внимание на третий абзац после 9.6 PUT : вы не заменяете объект по URL-адресу новым содержимым; вы просите объект по URL-адресу обработать некоторую информацию и разумно ответить в форме информативных представлений.В нашем случае мы просим логику модификации at
/v1/dogs/1/bark-schedule
(которая является аналогом логики отображения, которая сообщает нам, когда он в последний раз лаял и когда он будет лаять в следующий раз) обработать нашу информацию и соответствующим образом изменить некоторые представления. В ответ на futureGET
-объект логика отображения, соответствующая тому же URL-адресу, сообщит нам, что собака теперь лает так, как мы хотим.Думайте о работе cron как о детали реализации. HTTP занимается просмотром и изменением представлений. Теперь сервис будет сообщать клиенту, когда собака лаяла в последний раз и когда она будет лаять в следующий раз. С точки зрения сервиса, это честно, потому что это время соответствует прошлым и запланированным задачам cron.
источник
REST - это ресурсно-ориентированный стандарт, а не действия, как RPC.
Если вы хотите, чтобы ваш сервер лаял , вам следует изучить различные идеи, такие как JSON-RPC , или обмен данными через веб-сокеты.
На мой взгляд, каждая попытка сохранить его в RESTful потерпит неудачу: вы можете выдать a
POST
сaction
параметром, вы не создаете никаких новых ресурсов, но, поскольку у вас могут быть побочные эффекты, вы в большей безопасности.источник
POST
был разработан для «предоставления блока данных ... процессу обработки данных» . Кажется, что многие люди различают ресурсы от действий, но на самом деле действия - это просто тип ресурса. Вызов ресурса действия на сервере по-прежнему представляет собой единый интерфейс, кэшируемый, модульный и масштабируемый. Он также не имеет состояния, но это может быть нарушено, если клиент рассчитан на ответ. Но вызов «метода void» на сервере - это то, что Рой Филдинг намеревался использовать с REST .