Вызовите метод на стороне сервера для ресурса RESTful.

98

Имейте в виду, что у меня есть рудиментарное понимание 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:

  • Кора просто отправляет электронное письмо на dog.email и ничего не записывает.
  • bark отправляет электронное письмо на dog.email и увеличивает значение dog.barkCount на 1.
  • Кора создает новую запись "коры" с записью bark.timestamp, когда происходило образование коры. Он также увеличивает значение dog.barkCount на 1.
  • bark запускает системную команду, чтобы вытащить последнюю версию кода собаки из Github. Затем он отправляет текстовое сообщение владельцу собаки, сообщая им, что новый код собаки находится в производстве.
  • 13
    Интересно, что добавление щедрости привело к получению худших ответов, чем вы изначально получали ;-) При оценке ответов помните, что: 1) Спецификации для глаголов HTTP исключают любой выбор, кроме POST. 2) REST не имеет ничего общего со структурой URL - это общий список ограничений (без сохранения состояния, кэширование, многоуровневый, унифицированный интерфейс и т. Д.), Которые дают преимущества (масштабируемость, надежность, видимость и т. Д.). 3) Текущая практика (например, использование POST в спецификациях RPC) превосходит определения, которые составляют свои собственные правила API. 4) REST требует единого интерфейса (следуя спецификации HTTP).
  • 0
    @ Кирк, что ты думаешь о новых ответах? Есть ли что-то, что вы все еще хотите знать, но не были рассмотрены ни в одном из них? Я был бы более чем рад отредактировать свой ответ еще раз, если он может быть более полезным.
Показать ещё 3 комментария
Теги:
rest
url
api-design
restful-architecture

8 ответов

188
Лучший ответ

Для чего нужен дизайн RESTful?

Принципы RESTful обеспечивают функции, облегчающие веб-сайты (для случайного пользователя, который может "просматривать" их) для дизайна веб-сервисов, поэтому они легко для программиста. REST не хорош, потому что он ОТДЫХ, это хорошо, потому что это хорошо. И это хорошо в основном потому, что он прост.

Простота простого HTTP (без SOAP-конвертов и перегруженных сервисов с одним URI POST), что некоторые могут назвать "отсутствие функций" , на самом деле его наибольшая сила. С самого начала HTTP запрашивает у вас адресность и безгражданство: два базовых дизайнерских решения, которые поддерживают HTTP-масштабируемость до сегодняшних мега-сайтов (и мега-сервисов).

Но REST не является серебряным bulltet: Иногда стиль RPC ( "Удаленный вызов процедур" - например, SOAP) может быть подходящим, а иногда и другие потребности приоритет над достоинствами Сети. Это отлично. Нам не очень нравится - ненужная сложность. Слишком часто программист или компания привносят в RPC-стиле службы для работы, с которой простой старый HTTP может справиться просто отлично. Эффект заключается в том, что HTTP сводится к транспортному протоколу для огромной полезной нагрузки XML, которая объясняет, что происходит на самом деле (а не URI или HTTP-метод). Полученная услуга слишком сложна, невозможна для отладки и не будет работать, если у ваших клиентов нет точной установки, как предполагалось разработчиком.

Точно так же код Java/С# не может быть объектно-ориентированным, просто использование HTTP не делает проект RESTful. Можно с уверенностью сказать, что мышление связано с его услугами с точки зрения действий и удаленных методов, которые должны быть вызваны. Неудивительно, что в основном это будет связано с сервисом RPC-стиля (или REST-RPC-гибридом). Первый шаг - думать иначе. Дизайн RESTful может быть достигнут во многих отношениях, один из способов (простейший, некоторые могут сказать) - думать о вашем приложении с точки зрения ресурсов, а не действий:

  • Вместо того, чтобы думать в терминах действий ( "выполнять поиск мест на карте" ),
  • Подумайте о результатах этого действия ( "список мест на карте, соответствующих критериям поиска" ).

Я приведу примеры ниже. (Другой ключевой аспект REST - использование HATEOAS - я не чищу его здесь, но я говорю об этом быстро в другом сообщении.)

О первом дизайне

Посмотрим на предлагаемый дизайн:

ACTION http://api.animals.com/v1/dogs/1/

Во-первых, мы не должны рассматривать создание нового HTTP-глагола (ACTION). Вообще говоря, это нежелательно по нескольким причинам:

  • (1) Учитывая только URI службы, как "случайный" программист знает глагол ACTION существует?
  • (2), если программист знает, что он существует, как он узнает его семантику? Что означает этот глагол?
  • (3), какие свойства (безопасность, идемпотентность) следует ожидать, чтобы глагол имел?
  • (4) Что делать, если у программиста есть очень простой клиент, который обрабатывает только стандартные HTTP-глаголы?
  • (5)...

Теперь пусть рассмотрит использование POST (я расскажу о том, почему ниже, просто возьмите мое слово для этого сейчас):

POST /v1/dogs/1/ HTTP/1.1
Host: api.animals.com

{"action":"bark"}

Это может быть ОК... но , только если:

  • {"action":"bark"} был документом; и
  • /v1/dogs/1/ был "URI-обработчиком документов" (factory -like). "Процессор документов" - это URI, который вы просто "бросаете в вещи" и "забываете" о них - процессор может перенаправить вас на вновь созданный ресурс после "метания". Например. URI для размещения сообщений в службе брокера сообщений, которая после публикации перенаправит вас на URI, который показывает статус обработки сообщений.

Я не знаю много о вашей системе, но я уже поставил оба не верно:

  • {"action":"bark"} не документ, на самом деле - это метод, который вы пытаетесь прогнать ниндзя в службу; и
  • URI /v1/dogs/1/ представляет собой ресурс "собака" (возможно, собака с id==1), а не процессор документа.

Итак, теперь мы знаем, что дизайн выше не настолько RESTful, но что это такое? Что в этом плохого?В принципе, это плохо, потому что это сложный URI со сложными значениями. Вы ничего не можете сделать из этого. Как программист знал, что у собаки есть действие bark, которое может быть тайно введено с помощью POST в него?

Разработка ваших запросов API-вызовов

Итак, позвольте прервать погоню и попытайтесь спроектировать эти лавы RESTfully, думая с точки зрения ресурсов. Позвольте мне процитировать книгу Restful Web Services:

A POST запрос - попытка создать новый ресурс из существующего один. Существующий ресурс может быть родителем нового в смысл структуры данных, способ, которым корень дерева является родителем всех его листовые узлы. Или существующий ресурс может быть специальным "factory" ресурс, единственная цель которого - генерировать другие ресурсы. представление, отправленное вместе с запросом POST, описывает начальную состояние нового ресурса. Как и в случае PUT, запрос POST не требуется включают представление вообще.

Следуя приведенному выше описанию, мы можем видеть, что bark может быть смоделирован как подресурс dog (так как a bark содержится внутри собаки, т.е. кора "лает" на собаку).

Из того рассуждения, которое мы уже получили:

  • Метод POST
  • Ресурс /barks, подресурс собаки: /v1/dogs/1/barks, представляющий a bark "factory". Этот URI уникален для каждой собаки (поскольку он находится под /v1/dogs/{id}).

Теперь каждый случай вашего списка имеет определенное поведение.

1. кора просто отправляет электронное письмо на адрес dog.email и ничего не записывает.

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


1.1 bark отправляет электронное письмо на адрес dog.email и ничего не записывает (в качестве синхронной задачи)

Этот случай прост. Призыв к ресурсу barks factory дает кору (отправленное электронное письмо) сразу, и ответ (если OK или нет) предоставляется сразу:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(entity-body is empty - or, if you require a **document**, place it here)

200 OK

Поскольку он ничего не записывает (изменений), 200 OK достаточно. Это показывает, что все прошло так, как ожидалось.


1.2 кора посылает электронное письмо на адрес dog.email и ничего не записывает (как асинхронную задачу)

В этом случае клиент должен иметь способ отслеживать задачу bark. Задача bark должна быть ресурсом с его собственным URI.:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

{document body, if needed;
NOTE: when possible, the response SHOULD contain a short hypertext note with a hyperlink
to the newly created resource (bark) URI, the same returned in the Location header
(also notice that, for the 202 status code, the Location header meaning is not
standardized, thus the importance of a hipertext/hyperlink response)}

202 Accepted
Location: http://api.animals.com/v1/dogs/1/barks/a65h44

Таким образом, каждый bark прослеживается. Затем клиент может выдать GET в URI bark, чтобы узнать текущее состояние. Возможно, даже используйте DELETE, чтобы отменить его.


2. кора посылает электронное письмо на адрес dog.email, а затем увеличивает dog.barkCount на 1

Это может быть сложнее, если вы хотите сообщить клиенту, что ресурс dog изменился:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

{document body, if needed; when possible, containing a hipertext/hyperlink with the address
in the Location header -- says the standard}

303 See Other
Location: http://api.animals.com/v1/dogs/1

В этом случае заголовок заголовка location должен сообщить клиенту, что он должен взглянуть на dog. Из HTTP RFC о 303:

Этот метод существует прежде всего для того, чтобы POST -активен script, чтобы перенаправить пользовательский агент на выбранный ресурс.

Если задача асинхронная, необходим субресурс bark, как и в случае 1.2, а 303 должен быть возвращен при GET .../barks/Y, когда задача завершена.


3. Кора создает новую запись bark с записью bark.timestamp, когда произошла кора. Он также увеличивает dog.barkCount на 1.

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(document body, if needed)

201 Created
Location: http://api.animals.com/v1/dogs/1/barks/a65h44

Здесь bark создается из-за запроса, поэтому применяется статус 201 Created.

Если создание асинхронно, требуется 202 Accepted (как это делает HTTP RFC).

Сохраненная временная метка является частью ресурса bark и может быть получена с помощью GET к ней. Обновленная собака может быть "задокументирована" в этом GET dogs/X/barks/Y.


4. Кора запускает системную команду, чтобы вытащить последнюю версию кода собаки из Github. Затем он отправляет текстовое сообщение dog.owner, сообщая им, что новый код собаки находится в производстве.

Формулировка этого сложна, но в значительной степени это простая асинхронная задача:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(document body, if needed)

202 Accepted
Location: http://api.animals.com/v1/dogs/1/barks/a65h44

Затем клиент выдаст GET в /v1/dogs/1/barks/a65h44, чтобы узнать текущее состояние (если код был вынут, он был отправлен владельцу и тому подобное). Всякий раз, когда собака изменяется, применяется 303.


Завершение

Цитата Рой Филдинг:

Единственное, что REST требует от методов, состоит в том, чтобы они были равномерно определенная для всех ресурсов (т.е. чтобы посредники не знать тип ресурса, чтобы понять смысл запрос).

В приведенных выше примерах POST является равномерно разработанным. Это сделает собаку "bark". Это небезопасно (означает, что у коры есть влияние на ресурсы), ни идемпотент (каждый запрос дает новый bark), который хорошо подходит для глагола POST.

Программист знал бы: a POST to barks дает a bark. Коды статуса ответа (вместе с сущностью и заголовками, если необходимо) выполняют задание, объясняющее, что изменилось и как клиент может и должен действовать.

Примечание. Основными источниками были: Restful Web Services ", HTTP RFC и Блог Роя Филдинга.




Edit:

Вопрос и, таким образом, ответ сильно изменились с момента их создания. оригинальный вопрос спросил о дизайне URI, например:

ACTION http://api.animals.com/v1/dogs/1/?action=bark

Ниже приводится объяснение, почему это не лучший выбор:

Как клиенты сообщают серверу ЧТО ДЕЛАТЬ, данные - это информация о методе.

  • Веб-службы RESTful передают информацию о методе в методе HTTP.
  • Типичные RPC-стиль и SOAP-сервисы сохраняют их в заголовке сущности и HTTP-заголовке.

WHICH PART данных [клиент хочет сервер] для работы - это информация о области охвата.

  • Службы RESTful используют URI. Службы SOAP/RPC-Style снова используют заголовки сущностей и HTTP-заголовки.

В качестве примера возьмите URI Google http://www.google.com/search?q=DOG. Там информация о методе GET, а информация о области охвата - /search?q=DOG.

Короче говоря:

  • В архитектуре RESTful информация о методе переходит в метод HTTP.
  • В Ресурсно-ориентированных архитектурах информация о области охвата переходит в URI.

И эмпирическое правило:

Если метод HTTP не соответствует данным метода, служба isnt RESTful. Если информация о области охвата не указана в URI, служба не является ресурсо-ориентированной.

Вы можете поместить действие "коры" в URL (или в тело сущности) и использовать POST. Нет проблем, он работает и может быть самым простым способом сделать это, , но это не RESTful.

Чтобы ваш сервис действительно был RESTful, вам, возможно, придется сделать шаг назад и подумать о том, что вы действительно хотите здесь сделать (какие последствия он будет иметь для ресурсов).

Я не могу говорить о ваших конкретных бизнес-потребностях, но позвольте мне привести вам пример: рассмотрите службу заказа RESTful, где заказы находятся в URI, например example.com/order/123.

Теперь скажите, что мы хотим отменить заказ, как мы это сделаем? Может возникнуть соблазн подумать, что это "действие отмены" и создать его как POST example.com/order/123?do=cancel.

Это не RESTful, как мы говорили выше. Вместо этого мы могли бы PUT создать новое представление order с элементом canceled, отправленным в true:

PUT /order/123 HTTP/1.1
Content-Type: application/xml

<order id="123">
    <customer id="89987">...</customer>
    <canceled>true</canceled>
    ...
</order>

И что это. Если заказ не может быть отменен, может быть возвращен конкретный код состояния. (Конструкция подресурса, например 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 или HEAD - это запрос читать некоторые данные, а не запрос на изменение состояния сервера. Клиент может сделать запрос GET или HEAD 10 раз, и это то же самое, что сделать его один раз или никогда не делать вообще.

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

POST не является ни безопасным, ни идемпотентным. Создание двух идентичных запросов POST к ресурсу 'factory, вероятно, приведет к двум подчиненным ресурсам, содержащим одинаковые Информация. При перегрузке (метод в URI или сущности) POST все ставки отключены.

Оба этих свойства были важны для успеха протокола HTTP (над ненадежными сетями!): сколько раз вы обновили страницу (GET), не дожидаясь ее полной загрузки?

Создание действия и размещение его в URL-адресе явно нарушает контракт HTTP-методов. Еще раз, технология позволяет вам, вы можете это сделать, но это не дизайн RESTful.

  • 0
    Я согласен с идеей, что вызов действия на сервере, обозначенный как действие в URL, не является RESTful. POST был разработан для «предоставления блока данных ... процессу обработки данных» . Кажется, что многие отличают ресурсы от действий, но на самом деле действия - это просто тип ресурса.
  • 1
    @JacobStevens ОП немного изменил вопрос, поэтому я должен обновить свой ответ, чтобы сделать его более прямым (проверьте исходный вопрос , возможно, вы поймете, что я имею в виду). Я согласен с POST «предоставление блока данных ... процессу обработки данных», но на самом деле разница в том, что это блок данных , а не блок данных и процедура (действие, метод, команда) для быть исполненным на потом. Это перегрузка POST , а перегрузка POST - это дизайн в стиле RPC, а не RESTful.
Показать ещё 16 комментариев
5

я ответил ранее, но этот ответ противоречит моему старому ответу и следует совсем другой стратегии решения проблемы. Это показывает, как HTTP-запрос построен из концепций, определяющих REST и HTTP. Он также использует PATCH вместо POST или PUT.

Он проходит через ограничения REST, затем компоненты HTTP, а затем - возможное решение.

REST

REST - это набор ограничений, предназначенных для применения к распределенной системе гипермедиа, чтобы сделать его масштабируемым. Даже чтобы понять это в контексте дистанционного управления действием, вам нужно подумать о дистанционном контроле действия как части распределенной системы гипермедиа - части системы для обнаружения, просмотра и изменения взаимосвязанной информации. Если это больше проблем, чем стоит, то, вероятно, не стоит пытаться сделать это RESTful. Если вам просто нужен GUI типа "панель управления" на клиенте, который может инициировать действия на сервере через порт 80, то вам, вероятно, нужен простой интерфейс RPC, такой как JSON-RPC через HTTP-запросы/ответы или WebSocket.

Но REST - это увлекательный образ мышления, и пример в этом вопросе легко моделируется с помощью интерфейса RESTful, поэтому давайте возьмем вызов для удовольствия и образования.

REST определяется четырьмя ограничениями интерфейса:

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

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

Начнем с первого ограничения: идентификация ресурса.

Любая информация, которая может быть названа, может быть ресурсом: документ или изображение, временная служба (например, "сегодня погода в Лос-Анджелесе" ), коллекция других ресурсов, не виртуальный объект (например, человек), и т.д.

Итак, собака - это ресурс. Он должен быть идентифицирован.

Точнее, ресурс R представляет собой временно изменяющуюся функцию принадлежности M R (t), которая для времени t отображает на набор сущностей или значений, которые эквивалентны. Значениями в наборе могут быть представления ресурсов и/или идентификаторы ресурсов.

Вы моделируете собаку, беря набор идентификаторов и представлений и заявляя, что все они связаны друг с другом в данный момент времени. В настоящее время позвольте использовать идентификатор "dog # 1". Это приводит нас ко второму и третьему ограничениям: представление ресурсов и самоописание.

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

Ниже приведена последовательность байтов, фиксирующая предполагаемое состояние собаки, то есть представление, которое мы хотим связать с идентификатором "собака № 1" (обратите внимание, что он представляет только часть состояния, так как он не считает собаку имя, здоровье или даже прошлые лаки):

Он лает каждые 10 минут с момента его изменения и будет продолжаться бесконечно.

Предполагается, что он привязан к метаданным, которые его описывают. Эти метаданные могут быть полезны:

Это английское утверждение. Он описывает часть предполагаемого состояния. Если он принят несколько раз, разрешите только первый эффект.

Наконец, посмотрим на четвертое ограничение: HATEOAS.

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

В интерфейсе RESTful клиент получает представление ресурса, чтобы выяснить, как он должен получать или отправлять представление. Должно быть какое-то представление в приложении, из которого клиент может выяснить, как получать или отправлять все представления, которые он должен получать или отправлять, даже если он следует цепочке представлений, чтобы получить эту информацию. Это кажется достаточно простым:

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

HTTP

HTTP реализует ограничения REST следующим образом:

идентификация ресурса: URI

представление ресурса: entity-body

самоописание: код метода или состояния, заголовки и, возможно, части тела сущности (например, URI схемы XML)

HATEOAS: гиперссылки

Вы выбрали http://api.animals.com/v1/dogs/1 как URI. Предположим, что клиент получил это с некоторой страницы на сайте.

Позвольте использовать этот объект-тело (значение next является меткой времени, значение 0 означает "когда этот запрос получен" ):

{"barks": {"next": 0, "frequency": 10}}

Теперь нам нужен метод. PATCH соответствует описанию "части предполагаемого состояния", мы решили:

Метод PATCH запрашивает, чтобы набор изменений, описанных в объекте запроса, был применен к ресурсу, идентифицированному Request-URI.

И некоторые заголовки:

Чтобы указать язык тела объекта: Content-Type: application/json

Чтобы убедиться, что это происходит только один раз: If-Unmodified-Since: <date/time this was first sent>

И у нас есть запрос:

PATCH /v1/dogs/1/ HTTP/1.1
Host: api.animals.com
Content-Type: application/json
If-Unmodified-Since: <date/time this was first sent>
[other headers]

{"barks": {"next": 0, "frequency": 10}}

В случае успеха клиент должен получить 204 код статуса в ответ или 205, если представление /v1/dogs/1/ изменилось, чтобы отразить новый график лай.

При сбое он должен получить 403 и полезное сообщение.

Не обязательно REST для службы отражать расписание коры в представлении в ответ на GET /v1/dogs/1/, но это было бы наиболее разумно, если бы представление JSON включало это:

"barks": {
    "previous": [x_1, x_2, ..., x_n],
    "next": x_n,
    "frequency": 10
}

Рассматривайте задание cron как деталь реализации, которую сервер скрывает от интерфейса. Это красота универсального интерфейса. Клиент не должен знать, что делает сервер за кулисами; все, о чем он заботится, заключается в том, что служба понимает и отвечает запрошенным изменениям состояния.

4

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

API, такие как XMLRPC, используют POST для запуска действий, которые могут запускать произвольный код. "Действие" включено в данные POST:

POST /RPC2 HTTP/1.0
User-Agent: Frontier/5.1.2 (WinNT)
Host: betty.userland.com
Content-Type: text/xml
Content-length: 181

<?xml version="1.0"?>
<methodCall>
   <methodName>examples.getStateName</methodName>
   <params>
      <param>
         <value><i4>41</i4></value>
         </param>
      </params>
   </methodCall>

Приводится пример RPC, показывающий, что POST является обычным выбором HTTP-глаголов для серверных методов. Здесь мысли Роя Филдинга о POST - он в значительной степени говорит, что RESTful использует HTTP-методы, как указано.

Обратите внимание, что сам RPC не очень RESTful, потому что он не ориентирован на ресурсы. Но если вам нужна безгражданность, кеширование или расслоение, нетрудно сделать соответствующие преобразования. См. http://blog.perfectapi.com/2012/opinionated-rpc-apis-vs-restful-apis/ для примера.

  • 0
    Будет ли это выглядеть так: POST api.animals.com/v1/dogs/1/?action=bark
  • 0
    Я думаю, что вы бы URL кодировать параметры, не помещая его в строку запроса
Показать ещё 4 комментария
2

POST - метод HTTP, разработанный для

Предоставление блока данных... процессу обработки данных

Серверные методы обработки не-CRUD-отображаемых действий - это Рой Филдинг, предназначенный с REST, так что вы там хороши, и почему POST было сделано неидемпотентным. POST будет обрабатывать большинство сообщений на серверных методах обработки информации.

Тем не менее, в сценарии вашей собачьей лайки, если вы хотите, чтобы кору серверной стороны выполняли каждые 10 минут, но по какой-то причине требуется запуск триггера от клиента, PUT будет служить цели лучше, из-за его идемпотентности. Ну, строго по этому сценарию нет явного риска множественных запросов POST, заставляющих вашу собаку мяукать, но в любом случае цель этих двух подобных методов. Мой ответ на аналогичный вопрос SO может быть вам полезен.

  • 1
    PUT vs. POST - это все о URL. В третьем абзаце после 9.6 PUT говорится, что целью этих двух методов является то, что URL-адрес PUT относится к тому, что должно быть заменено контентом клиента, а URL-адрес POST относится к тому, что должно обрабатывать содержимое клиента так, как он хочет.
1

Если мы предположим, что Barking является внутренним/зависимым/вспомогательным ресурсом, на который может воздействовать потребитель, тогда можно сказать:

POST http://api.animals.com/v1/dogs/1/bark

собака номер 1 лает

GET http://api.animals.com/v1/dogs/1/bark

возвращает последнюю метку времени коры

DELETE http://api.animals.com/v1/dogs/1/bark

не применяется! поэтому игнорируйте его.

  • 0
    Это только RESTful, если вы считаете /v1/dogs/1/bark ресурсом как таковым , а POST - описанием того, как внутреннее состояние этого ресурса должно измениться. Я считаю, что имеет больше смысла просто рассматривать /v1/dogs/1/ как ресурс и указывать в теле сущности, что он должен лаять.
  • 0
    ммм .. ну, это ресурс, который вы можете изменить его состояние. Потому что в результате изменения его состояния шумит, а не уменьшается ресурс! Вы смотрите на Барка как на глагол (то есть), поэтому вы не можете считать его ресурсом. Я рассматриваю его как зависимый ресурс, состояние которого можно изменить, и, поскольку его состояние является логическим, я не вижу причин упоминать его в объекте-теле. Это только мое мнение.
1

В предыдущих версиях некоторых ответов вы предлагали использовать RPC. Вам не нужно искать RPC, так как вы можете делать то, что хотите, придерживаясь ограничений REST.

Во-первых, не указывайте параметры действия в URL. URL-адрес определяет, к чему вы применяете действие, и параметры запроса являются частью URL-адреса. Его следует рассматривать исключительно как существительное . http://api.animals.com/v1/dogs/1/?action=bark - это другой ресурс - другое существительное - http://api.animals.com/v1/dogs/1/. [Нотабене Asker удалил URI ?action=bark из вопроса.] Например, сравните http://api.animals.com/v1/dogs/?id=1 с http://api.animals.com/v1/dogs/?id=2. Различные ресурсы, выделенные только строкой запроса. Таким образом, действие вашего запроса, если оно не соответствует непосредственно существующему типу метода bodyless (TRACE, OPTIONS, HEAD, GET, DELETE и т.д.), Должно быть определено в теле запроса.

Затем определите, является ли действие " idempotent", что означает, что его можно повторить без неблагоприятного эффекта (см. следующий абзац для более подробного объяснения), Например, установка значения true может быть повторена, если клиент не уверен в том, что желаемый эффект произошел. Они снова отправляют запрос, и значение остается верным. Добавление 1 к числу не является идемпотентным. Если клиент отправляет команду Add1, не уверен, что он сработал, и отправляет его еще раз, добавил ли сервер один или два? После того, как вы определили, что у вас есть лучшее место для выбора между PUT и POST для вашего метода.

Idempotent означает, что запрос может быть повторен без изменения результата. Эти эффекты не включают регистрацию и другие действия администратора сервера. Используя первый и второй примеры, отправка двух электронных писем одному человеку приводит к другому состоянию, чем отправка одного электронного письма (у получателя есть два в своем почтовом ящике, который они могут считать спамом), поэтому я бы определенно использовал POST для этого, Если barkCount в примере 2 предназначен для просмотра пользователем вашего API или затрагивает то, что видимо для клиента, то это также то, что сделало бы запрос неидемпотентным. Если он должен быть просмотрен только вами, он учитывается как ведение журнала сервера и должен быть проигнорирован при определении idempotentcy.

Наконец, определите, можно ли ожидать, что действие, которое вы хотите выполнить, преуспеть немедленно или нет. BarkDog - это быстро завершающее действие. RunMarathon - нет. Если ваше действие происходит медленно, подумайте о возврате 202 Accepted с URL-адресом в теле ответа для опроса пользователя, чтобы узнать, завершено ли действие. Кроме того, у пользователей POST есть URL-адрес списка, например /marathons-in-progress/, а затем, когда действие будет выполнено, перенаправляйте их с URL-адреса прогресса в URL-адрес /marathons-complete/.
Для конкретных случаев № 1 и № 2 у меня будет очередь хоста сервера, и клиент отправляет партии адресов к нему. Действие не будет SendEmails, но что-то вроде AddToDispatchQueue. Затем сервер может опросить очередь, чтобы узнать, есть ли какие-либо адреса электронной почты, и отправить электронные письма, если они найдут. Затем он обновляет очередь, чтобы указать, что ожидающее действие теперь выполнено. У вас будет другой URI, показывающий клиенту текущее состояние очереди. Чтобы избежать двойной отправки сообщений электронной почты, сервер также мог сохранить журнал того, кому он отправил это письмо, и проверить каждый адрес на это, чтобы гарантировать, что он никогда не отправит два на тот же адрес, даже если вы дважды отправляете один и тот же список очередь.

При выборе URI для чего-либо, попробуйте думать об этом как результат, а не о действии. Например, google.com/search?q=dogs показывает результаты поиска слова "собаки". Это не обязательно выполняет поиск.

Случаи №3 и №4 из вашего списка также не являются идемпотентными действиями. Вы предполагаете, что различные предлагаемые эффекты могут повлиять на дизайн API. Во всех четырех случаях я бы использовал один и тот же API, поскольку все четыре меняют "мировое состояние".

  • 0
    Допустим, действие состоит в том, чтобы пройти через огромную очередь электронной почты и отправить сообщение группе людей. Это идемпотент? Идемпотентные действия для PUT или POST?
  • 0
    @kirk Я расширил свой ответ.
0

См. мой новый ответ. Это противоречит этому и объясняет REST и HTTP более четко и точно.

Здесь рекомендация, которая оказалась RESTful, но, конечно, не единственная опция. Чтобы начать лаять, когда услуга получает запрос:

POST /v1/dogs/1/bark-schedule HTTP/1.1
...
{"token": 12345, "next": 0, "frequency": 10}

token - произвольное число, которое предотвращает избыточные лаки, независимо от того, сколько раз этот запрос отправляется.

next указывает время следующей коры; значение 0 означает "ASAP".

Всякий раз, когда вы GET /v1/dogs/1/bark-schedule, вы должны получить что-то вроде этого, где t - время последней коры, и u равно t + 10 минут:

{"last": t, "next": u}

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

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

Объяснение

REST

pub?w=400

Забудьте об 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? Может быть, с фотографией. Может быть, с набором рентгеновских лучей. Или, может быть, с указанием даты и времени, когда R последний лаял. Но помните, что это все представления одного и того же ресурса. /v1/dogs/1/x-rays является идентификатором того же ресурса, который представлен ответом на вопрос "когда была R последняя кора?"

HTTP

pub?w=400

Несколько представлений ресурса не очень полезны, если вы не можете ссылаться на тот, который вам нужен. Вот почему HTTP полезен: он позволяет связывать идентификаторы с представлениями. То есть, это способ для службы получить URL-адрес и решить, какое представление будет обслуживать клиент.

По крайней мере, то, что делает GET. PUT в основном является обратным к GET: you PUT представление r в URL-адресе, если вы хотите, чтобы будущие запросы GET к этому URL-адресу возвратили r, с некоторыми возможными переводами, такими как JSON в HTML.

POST является более свободным способом изменения представления. Подумайте, есть ли логика отображения и логика модификации, которые являются аналогами друг друга - оба соответствуют одному и тому же URL. Запрос POST - это запрос логики модификации для обработки информации и изменения любых представлений (а не только представления, расположенного по тому же URL-адресу), что и служба. Обратите внимание на третий абзац после 9.6 PUT: вы не заменяете вещь на URL с новым контентом; вы запрашиваете у объекта URL-адрес для обработки некоторой информации и интеллектуального ответа в форме информационных представлений.

В нашем случае мы запрашиваем логику модификации в /v1/dogs/1/bark-schedule (которая является аналогом логики отображения, которая сообщает нам, когда она в последний раз лает и когда она будет следующей корой) обрабатывать нашу информацию и соответственно модифицировать некоторые представления. В ответ на будущие GET s логика отображения, соответствующая тому же URL-адресу, сообщит нам, что собака теперь лает по своему желанию.

Подумайте о задании cron как о деталях реализации. HTTP имеет дело с просмотром и модификацией представлений. С этого момента служба сообщит клиенту, когда собака наконец лает, и когда она будет лаять дальше. С точки зрения обслуживания, это честно, потому что эти времена соответствуют прошлым и запланированным заданиям cron.

0

REST - это ориентированный на ресурсы стандарт, это не действие, управляемое как RPC.

Если вы хотите, чтобы ваш сервер лаял, вы должны изучить различные идеи, такие как JSON-RPC, или в обмен сообщениями в сети.

Каждая попытка сохранить RESTful на мой взгляд: вы можете выдать POST с параметром action, вы не создаете никаких новых ресурсов, но поскольку у вас могут быть побочные эффекты, вы более безопасны.

  • 0
    POST был разработан для «предоставления блока данных ... процессу обработки данных» . Кажется, что многие отличают ресурсы от действий, но на самом деле действия - это просто тип ресурса. Вызов ресурса действия на сервере все еще является единым интерфейсом, кешируемым, модульным и масштабируемым. Он также не имеет состояния, но это может быть нарушено, если клиент рассчитан на ответ. Но вызов «пустого метода» на сервере - это то, что Рой Филдинг намеревался использовать с REST .
  • 0
    Как я описываю в своем ответе , вы можете в REST неявно заставить сервер выполнить действие, попросив его теперь сказать «ваше действие выполнено», тогда как RPC основан на идее простого запроса сервера на выполнение Действие. Оба имеют смысл, так же, как императивное и декларативное программирование имеют смысл.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню