Подтвердить что ты не робот

Где в архитектуре HATEOAS вы указываете HTTP-глаголы?

Я читал статью в HATEOAS, и хотя я понимаю идею предоставления URL-адресов для дальнейших действий в ответе я не вижу, где вы указываете, какие HTTP-глаголы должны использоваться для взаимодействия с этими URL-адресами.

Например, из Что такое HATEOAS и почему это важно для моего REST API?, как из этого ответа

GET /account/12345 HTTP/1.1

HTTP/1.1 200 OK
<?xml version="1.0"?>
<account>
    <account_number>12345</account_number>
    <balance currency="usd">100.00</balance>
    <link rel="deposit" href="/account/12345/deposit" />
    <link rel="withdraw" href="/account/12345/withdraw" />
    <link rel="transfer" href="/account/12345/transfer" />
    <link rel="close" href="/account/12345/close" />
</account

Знаете ли вы, должен ли я выпустить HTTP PUT или POST в /account/12345/close?

4b9b3361

Ответ 1

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

Если мы возьмем Роя Филдинга на его слове, невозможно написать большинство коммерческих интерактивных клиентских приложений как SOA RESTful/HATEOAS с использованием HTTP/HTML. Это возможно в других средах, я не могу сказать.

Таким образом, практический ответ: "Посмотрите в документации" и "напишите своему клиенту с этим приложением-знанием в нем" с побочной поддержкой "игнорируйте тот факт, что мы нарушаем правила Fielding, делая это".

Я склонен проектировать ответы JSON, которые обеспечивают такой подход:

GET /account/12345 HTTP/1.1
{
    "account": {
        "number": "12345",
        "currency": "usd",
        "balance": "100.00",
        "deposit": {
            "href": "/account/12345/deposit",
            "action": "POST"
        },
        "withdraw": {
            "href": "/account/12345/withdraw",
            "action": "POST"
        },
        "transfer": {
            "href": "/account/12345/transfer",
            "action": "POST"
        },
        "close": {
            "href": "/account/12345/close",
            "action": "DELETE"
        }
    }
}

... добавление дополнительных свойств в проект по мере необходимости, но это основы.

Я считаю, что это позволяет потребителю (клиентам) потребления писать RESTful способом, но при этом я использую Body Response, который Fielding говорит не о том, что он намеревался.

Я бы предложил это объяснение отдельно от ответа:


Филдинг говорит: "Меня расстраивает количество людей, вызывающих любой HTTP-интерфейс REST API". (http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven).

Обратите внимание, как он так остро говорит "любой" HTTP-интерфейс.

Наиболее значимым сегментом в его "лекции" является следующее:

" API REST должен вводиться без предварительного знания за пределами исходного URI (закладки) и набора стандартных типов медиа, подходящих для целевой аудитории (т.е. ожидается, что их понимают любые клиент, который может использовать API). С этого момента все переходы состояния приложения должны управляться клиентским выбором предоставленных сервером вариантов, которые присутствуют в полученных представлениях или подразумеваются пользователями, манипулирующими этими представлениями. Переходы могут быть определены (или ограниченный) знаниями клиентов о типах медиа и механизмах обмена ресурсами, которые могут быть улучшены" на лету "(например, по запросу). [Сбой здесь означает, что во внеполосной информации взаимодействие вместо гипертекста.]"

Он говорит об этом, потому что тип URI для HTTP/HTML-приложений - это просто "text/html", и где этот глагол? Нет. URI не может рассказать вам, что для чего-то требует Verb для использования/навигации, ergo вы не можете использовать только данные внутри диапазона, чтобы динамически строить "следующую" навигацию в своем клиенте.

Он объяснил, что, по его мнению, мы предоставляем наш URI в составе CDATA, который включает в себя "метод", или что контекст URI сам по себе обеспечит его, как это делает элемент FORM. Он явно рельсы против API OpenSocialst REST, заявляя, что он не RESTful.

Здесь: "Элементы привязки с атрибутом href создают гипертекстовую ссылку, которая при выборе вызывает запрос на поиск (GET) в URI, соответствующий атрибуту href, кодируемому CDATA". Идентификаторы, методы и типы носителей являются ортогональными проблемами - методы не задаются типом медиа. Вместо этого тип носителя сообщает клиенту, какой метод использовать (например, якорь подразумевает GET) или как определить используемый метод (например, элемент формы говорит, чтобы искать в атрибуте метода). Клиент должен уже знать, что означают методы (они универсальны) и как разыменовывать URI.

Обратите внимание, что он говорит, что Клиент уже должен знать, что означают эти методы, он не говорит, что Клиент должен уже знать, что это такое - именно поэтому вы задали свой вопрос. Многие люди борются с этим, потому что мы фактически не создаем наши приложения, как это, в большинстве сред SOA.

Как и многие инженеры, я просто хочу, чтобы Филдинг выступила с разъяснением или повторным выражением, но не только он этого не сделал, он опубликовал еще два указаний на нас как инженеров, удвоив его выражение, говоря, что мы должны перестать называть наш API RESTful и признать, что мы создаем RPC.

Я думаю, что подобный JSON подход - это мост reasoble, но у меня нет ответа на то, что мы используем тело запроса, чтобы сделать это, а не полагаться на тип носителя, чтобы это подразумевалось.

Наконец, в HTTP есть более новый Verb, называемый OPTIONS, который для данного URI вернет разрешенный список действий Verb. Я думаю, что у Филдинга была написана эта HTTP-версия. Это позволило бы Клиенту в целом создавать URI-навигацию без запрещенного внутреннего знания приложений. Но у меня есть три вопроса, которые я могу придумать в практическом мире:

  • Вам нужно будет закодировать механизм в своей агрегированной службе, чтобы сделать этот вызов для каждого URI, который вы пытаетесь вернуть, и поскольку многие данные содержат много URI (_links в HAL), которые добавляют много дополнительных "перелетов" в вашу службу Конструкция ответа. Вероятно, мы все будем жаловаться на это.
  • Практически ни один SOA-сайт, претендующий на RESTful, фактически реализует вызов-метод-метод OPTIONS, чтобы вы могли выполнить этот запрос в любом случае.
  • Мы все будем жаловаться на "ненужные" дополнительные призывы, которые он добавляет (особенно в мире eCommerce) к обработке Клиента и его тенденцию подталкивать нас к требованиям SLA.

Ответ 2

Не помещает глаголы в ваши URI (например,/account/12345/ transfer). URI представляют ресурсы, а не действия.

Используемые глаголы определяются протоколом HTTP (например, GET, POST, PUT, OPTIONS, DELETE и т.д.). REST - это архитектура с набором ограничений, а HTTP - это протокол, который придерживается этих ограничений. HTTP определяет ограниченный набор глаголов для передачи состояния ресурса с клиента на сервер и наоборот. По определению вы ограничены только этими глаголами.

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

Если клиент должен знать, какие глаголы он может использовать на ресурсе, он может запросить ресурс с помощью глагола OPTIONS и посмотреть заголовок Allow в ответе (при условии, что сервер вернет эту информацию, которая должна быть, если она быть полезным). Некоторые ресурсы могут принимать только GET, в то время как другие могут принимать других, таких как POST и PUT.

Посмотрите на спецификацию HTTP, чтобы узнать, какой глагол использовать в каком контексте.

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

/accounts/12345

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

PUT /accounts/12345

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

PUT /accounts/12345

<?xml version="1.0"?>
<account>
    <account_number>12345</account_number>
    <balance currency="usd">100.00</balance>
    <state>closed</state>
</account>

Ресурс на сервере теперь отражает ресурс на клиенте. Оба находятся в закрытом состоянии. Если вы не хотите передавать весь ресурс каждый раз, когда вы вносите изменения в один из его атрибутов, вы можете разделить их на иерархию ресурсов. Сделайте статус учетной записи своим собственным ресурсом и PUT, чтобы изменить его

PUT /accounts/12345/status

<?xml version="1.0"?>
<state>closed</state>

Ответ 3

Знаете ли вы, хотите ли вы PUT или POST в /account/ 12345/close?

Проконсультируйтесь с документацией по API, как вы знаете. HATEOS не является заменой официальной документации. Документация необходима для API REST, как и любой другой API.

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

Если вы хотите узнать, как использовать REST API, прочитайте документацию. Если вы хотите, чтобы кто-то другой использовал ваш REST API, предоставить им документацию.

Здесь нет волшебства.

Ответ 4

@Cormac Mulhall ответ очень хороший, но я хотел бы предложить уточнение, которое я слышал от коллеги:

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

Предположим, что порядки имеют несколько состояний жизненного цикла. В какой-то момент после составления проекта заказ помещается, выполняется или отменяется.

Информация об этих действиях заказа будет размещаться путем помещения имени действия в форме множественного существительного в пути ресурса с помощью /actions для возврата сведений, если состояние действия активно, или 404 NOT FOUND в противном случае.

https://order.api.foobar.com/v1.0/orders/{orderId}/actions/placements
https://order.api.foobar.com/v1.0/orders/{orderId}/actions/fulfillments
https://order.api.foobar.com/v1.0/orders/{orderId}/actions/cancellations

Если эти действия идемпотентны (заказ не может быть помещен дважды в строку), то эти действия могут быть запрошены с помощью PUT ing соответствующего представления для этих URI. Когда они не являются идемпотентными, они создаются с помощью POST в форме множественного числа.

Например, чтобы отслеживать порядок согласования, мы могли бы POST:

https://order.api.foobar.com/v1.0/orders/{orderId}/approvals

а затем мы увидим информацию об отдельных утверждениях, выполнив GET:

https://order.api.foobar.com/v1.0/orders/{orderId}/approval/1

Часто полезно использовать агрегат, называемый "действия", чтобы найти все действия:

https://order.api.foobar.com/v1.0/orders/{orderId}/actions

Мы могли бы POST к этому, позволяя объявлению объявить, какой тип действия подразумевается.

Вы также можете получить список действий по отдельным заказам, оставив параметр {orderId} выключенным:

https://order.api.foobar.com/v1.0/orders/actions/placements
https://order.api.foobar.com/v1.0/orders/actions

Их можно найти, добавив параметры запроса:

https://order.api.foobar.com/v1.0/orders/actions/placements?since={sinceTimestamp}