Находите спокойный ресурс при использовании HATEOAS?

Читая об ограничении HATEOAS/Hypermedia, я часто вижу, что у ресурса должен быть какой-то вид self/href. Аргументом для этого является то, что клиенту не нужно знать, как создать URL для этого конкретного ресурса, например. для обновления ресурса.

e.g.

{
     //instead of "id":"123"
     "href":"/api/v1/orders/123",

     order state...
}

Мне нравится эта идея.

Но как эта концепция согласуется с получением данных? Допустим, мне нужно получить заказ с определенным идентификатором заказа, как клиент справится с этим? Мне все еще нужно знать, как построить URL-адрес для ресурса в этом случае, верно?

Откуда клиент должен знать, где и как искать ресурс? Он должен так или иначе знать об URL-адресах API?


person Roger Johansson    schedule 25.01.2015    source источник
comment
Откуда необходимость получать по идентификатору? Каков реальный вариант использования?   -  person Pete    schedule 25.01.2015
comment
Приложение на стороне сервера отображает ссылку на приложение на стороне клиента для редактирования определенного заказа на основе идентификатора заказа. пользователь щелкает ссылку, приложение на стороне клиента открывает upp и ему нужно получить заказ ... должно быть довольно распространенным сценарием (?)   -  person Roger Johansson    schedule 25.01.2015
comment
Является ли клиентское приложение динамическим? Это означает, что вы не перезагружаете страницы, а выполняете переходы между состояниями с использованием XHR?   -  person Pete    schedule 25.01.2015
comment
Да, приложение типа SPA, но открывается из пользовательского интерфейса серверного приложения, в этом случае сервер не знает об остальных API, он получает идентификатор заказа из БД.. (устаревшее приложение переносится в SPA)   -  person Roger Johansson    schedule 25.01.2015
comment
Тогда ответ Стефана, вероятно, вам нужен. Процесс и шаблон URI RFC 6570 для «внедрения состояния» с вашего устаревшего сервера в REST API.   -  person Pete    schedule 25.01.2015
comment
После перехода из устаревшего состояния в состояние REST API вы можете переходить оттуда по ссылкам для любых дальнейших переходов состояний.   -  person Pete    schedule 25.01.2015


Ответы (4)


Хорошо спроектированный HATEOAS API будет иметь четкие точки входа, и остальную часть поведения приложения можно будет обнаружить оттуда.

Поскольку вопрос касается HATEOAS, я бы сказал, что использование шаблона URI возлагает на клиента слишком большую ответственность. . Вместо этого вы должны указать явный URL-адрес для каждого допустимого действия над ресурсом с учетом текущего состояния приложения.

Это не просто стилистический момент. Если сервер предоставляет шаблон, то разработчик клиента должен написать код для заполнения шаблона, что создает связь между ними. Теперь вы не можете изменить структуру URL-адреса на стороне сервера, не нарушив контракт с его клиентами. С HATEOAS вы связываете URL-адрес с каждым действием, разрешенным на ресурсе, и клиент просто заботится о действии. URL-адрес фактически является непрозрачным дескриптором: "Выберите свое собственное приключение", как — говорит Ян Робинсон.

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

Помните, что то, что вы получаете по сети, — это всего лишь представление ресурса (REST расшифровывается как REpresentational State Transfer). Могут быть разные представления одного и того же ресурса в зависимости от вашего текущего контекста, скажем, вашего текущего набора разрешений и текущего состояния приложения. Разные представления могут правомерно предлагать разные последующие действия.

Используя ваш пример, владелец заказа может увидеть это:

{
  "id": "/api/v1/orders/123", // reference to the current resource
  "rel": {
    "cancel": {
      "url": "/api/v1/orders/cancel?order_id=123",
      "method": "POST",
      // Metadata about what the cancel operation returns...
    },
    "list_orders": {
      "url": "/api/v1/orders",
      "method": "GET",
      // Metadata about what the list_orders operation returns...
    },
    // ...
    // Other operations available to the owner
  },
  // ...
  // Order state
}

Здесь я определяю карту, которая использует ключ в качестве имени операции или отношение в терминологии HATEOAS, хотя я мог бы также иметь список карт с ключом с именем "rel" и значениями "cancel" и "list_orders" соответственно. .

Другая роль, например координатор доставки, может не видеть операцию cancel, поскольку у нее нет разрешения на отмену заказа.

person Daniel Terhorst-North    schedule 25.01.2015
comment
Не приближаются ли ссылки rel к добавлению новых глаголов в стек в опасной близости? у меня сложилось впечатление, что ссылки предназначались для ссылок на другие ресурсы, а не как фасад для новых глаголов для ссылки на себя? - person Roger Johansson; 25.01.2015
comment
rel определяет отношения между ресурсами. Если глагол интересен, он будет представлен своим собственным ресурсом, поэтому ресурс, на который ссылается действие cancel, может быть OrderCancellation. Это будет овеществленная версия операции по отмене заказа. - person Daniel Terhorst-North; 26.01.2015
comment
Типы отношений ссылок можно использовать для документирования семантики заполнения шаблонов URI. Да, это создает связь, однако именно связь может развиваться, потому что в будущем могут использоваться новые отношения связи. REST не устраняет связь полностью, он просто сосредотачивается на связях в типах мультимедиа и типах отношений ссылок, чтобы их было легче идентифицировать и управлять ими. - person Darrel Miller; 26.01.2015
comment
Оглядываясь назад на этот ответ, часть обнаружения звучит для меня как GraphQL. Точка входа для обнаружения API — это анализ схемы GraphQL. - person user10375; 18.05.2019

Вы делаете это, используя ту же концепцию, что и в любом веб-приложении: отправляя клиенту рецепт для создания следующего запроса. В HTML для этого вы использовали бы HTML-форму. Если вы используете JSON, ваш формат должен иметь ту же концепцию, например. используя шаблон URI или даже форму, то есть список пар ключ-значение, возможно, с уже заполненными некоторыми значениями.

Например, предыдущий запрос может вернуть что-то вроде этого:

{ "order": {
    "link": {
        "template": "https://your-api.com/orders/{id}",
        "method": "GET",
        "type": "application/json"
    }
  }
}

Конечно, ваш код по-прежнему будет зависеть от некоторой информации — в данном случае от того факта, что идентификатор называется «id» в шаблоне. Но, добавляя эту косвенность, он не знает о фактическом URI. Также обратите внимание, что я добавил параметры метода и типа в качестве примера; решите ли вы сделать это настраиваемым, зависит от используемого вами формата. Для более подробного примера см. (или используйте) превосходный формат коллекция+json.

person Stefan Tilkov    schedule 25.01.2015
comment
Итак, скажем, у нас есть форма редактирования, тогда рабочий процесс будет примерно таким: -> запросить root /api -> ответ вашего примера -> URL-адрес сборки -> порядок запроса. это правильно понял? - person Roger Johansson; 25.01.2015

Хотя вы можете предоставить шаблон URI, я всегда считаю, что это немного запах, когда я должен это сделать. Иногда это необходимо, но если большая часть моего API использует этот подход, я бы не стал называть его HATEOAS или уровень 3 REST API.

Способ моделирования сценария во многом зависит от контекста, и, вероятно, поэтому Пит спрашивает о варианте использования.

Часто вы можете моделировать RESTful API так же, как вы моделируете веб-сайт, удобный для использования человеком. Например, у вас может быть ресурс, в котором перечислены все заказы пользователя, отсортированные, например. сначала самые последние заказы:

{
    "orders": [
        {
            "date": "2015-01-25",
            "total": 1234,
            "links": [
                {
                    "rel": "order",
                    "href": "https://follow.the.link"
                }
            ]
        },
        {
            "date": "2015-01-22",
            "total": 1337,
            "links": [
                {
                    "rel": "order",
                    "href": "https://follow.this.other.link"
                }
            ]
        }
    ]
}

Клиент может искать нужный ему заказ в этом списке, а затем, как только он идентифицирует интересующий заказ, может перейти по соответствующей ссылке с типом отношения «заказ».

В качестве общего ресурса Пособие по веб-сервисам RESTful незаменим для ответов на такого рода вопросы.

person Mark Seemann    schedule 25.01.2015
comment
Точно ответ в моей голове. Необходимость перехода от устаревшей системы к REST API, по-видимому, требует компрометации шаблона URI. - person Pete; 25.01.2015
comment
Считаете ли вы, что HTML FORM используется для поиска запаха RESTful? - person Darrel Miller; 26.01.2015
comment
@DarrelMiller Я бы не стал использовать HTML-форму, потому что это обычно заставляло бы клиентов менять «набор представлений»; клиенты обычно используют либо JSON, либо XML, так зачем заставлять их внезапно использовать HTML? - person Mark Seemann; 26.01.2015

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

Ключ в том, чтобы не возвращать значение, а только возвращать представление.

Мы используем платформу для этой реализации. Он имеет уникальный язык, основанный на взаимодействии. Платформа, поскольку она полностью совместима с HATEOAS, возвращает URL-адрес, когда на нее отправляется поиск.

В вашем примере, если мы отправим идентификатор бронирования. Он возвращает все URL-адреса заказов, которые имеют этот идентификатор бронирования. Затем клиент может перемещаться по этим URL-адресам.

Я надеюсь, что это поможет с вашим запросом.

person Antony gonzalves    schedule 26.02.2015