it-roy-ru.com

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

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

  1. кора просто отправляет электронное письмо на адрес dog.email и ничего не записывает.
  2. барк отправляет электронное письмо на адрес dog.email и увеличивает значение dog.barkCount на 1.
  3. bark создает новую запись "bark" с записью bark.timestamp при появлении коры. Это также увеличивает dog.barkCount на 1.
  4. барк запускает системную команду, чтобы вытащить последнюю версию кода собаки из Github. Затем он отправляет текстовое сообщение dog.owner, сообщающее им, что новый код собаки находится в производстве.
130
Kirk Ouimet

Зачем стремиться к 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 - я не рассматриваю это здесь, но говорю об этом быстро в другом посте .)

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

Давайте рассмотрим предложенный дизайн:

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 типа "обработчик документов". "Обработчик документов" - это URI, который вы просто "выбросили" и "забыли" о них - процессор может перенаправить вас на вновь созданный ресурс после "выброса". Например. URI для публикации сообщений в службе брокера сообщений, которая после публикации перенаправит вас на URI, который показывает состояние обработки сообщения.

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

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

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

Разработка вызовов API вашего вопроса

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

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

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

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

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

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

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

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


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

Этот случай прост. Вызов фабричного ресурса barks сразу же дает лай (отправленное электронное письмо), и сразу же дается ответ (если он в порядке или нет):

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-активированного сценария для перенаправления пользовательского агента на выбранный ресурс.

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


3. bark создает новую запись "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. bark запускает системную команду, чтобы вытащить последнюю версию кода собаки из 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

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


Завершение

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

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

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

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

Примечание. Использовались следующие основные источники: книга " Restful Web Services ", HTTP RFC и блог Роя Филдинга .




Edit:

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

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

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

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

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

КАКАЯ ЧАСТЬ данных [клиент хочет, чтобы сервер] оперировал, является областью информации .

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

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

Короче:

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

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

Если метод HTTP не соответствует информации о методе, служба не является 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 в /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 раз, и это то же самое, что сделать его один раз, или вообще не делать его .

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

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

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

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

256
acdcjunior

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

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

REST

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

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

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

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

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

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

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

Так что собака это ресурс. Это должно быть идентифицировано.

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

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

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

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

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

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

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

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

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

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

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

HTTP

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

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

представление ресурса : объект-тело

самоописание : метод или код состояния, заголовки и, возможно, части тела объекта (например, 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 как к деталям реализации, которые сервер скрывает от интерфейса. В этом прелесть универсального интерфейса. Клиент не должен знать, что сервер делает за кулисами; все, что его волнует, - это то, что служба понимает и отвечает на запрошенные изменения состояния.

6
Jordan

Большинство людей используют 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 - он в значительной степени говорит, что REST полезно использовать методы HTTP, как указано.

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

3
Raymond Hettinger

POST - это разработан метод HTTP для

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

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

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

2
Jacob Stevens

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

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

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

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

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

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

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

1
Nicholas Shanks

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

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

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

1
bolbol

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

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

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

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

next указывает время следующей коры; значение 0 означает "КАК МОЖНО СКОРЕЕ".

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

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

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

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

Объяснение

REST

Забудьте о HTTP на мгновение. Важно понимать, что resource - это функция, которая принимает время как ввод и возвращает набор, содержащий идентификаторы и представления . Давайте упростим это: ресурс - это набор 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

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

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

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

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

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

0
Jordan