Могу ли я иметь несколько отношений ссылок с одним и тем же URI в HATEOAS?

У меня есть ресурс, в этом случае:

http://www.domain.com/sales-rep/{id}

У каждого торгового представителя есть несколько продуктов, которые они могут продавать. URI для этого ресурса будет следующим:

http://www.domain.com/sales-rep/{id}/products

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

Моя проблема заключается в разработке отношений ссылок при получении ресурса торгового представителя. Например, мой JSON может выглядеть следующим образом:

{ 
  firstname : "Dave",
  lastname : "Matthews",
  links : [ 
    { rel : "self", href : "http://www.domain.com/sales-rep/dmat1" },
    { rel : "products", href : "http://www.domain.com/sales-rep/dmat1/products" }
  ] 
}

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

    { 
      firstname : "Dave",
      lastname : "Matthews",
      links : [ 
        { rel : "self", href : "http://www.domain.com/sales-rep/dmat1" },
        { rel : "view-products", href : "http://www.domain.com/sales-rep/dmat1/products",
        { rel : "edit-products", href : "http://www.domain.com/sales-rep/dmat1/products" }
      ] 
    }

Что-то подобное может работать, упрощая клиенту создание меню с правильными ссылками на основе наличия edit-products rel. Затем кюри для двух разных ссылок будут ссылаться на разные разделы документации, один для GET и PUT соответственно. Но имеет ли это смысл? Оба подхода кажутся мне неправильными.


person mogronalol    schedule 08.07.2015    source источник


Ответы (1)


Короткий ответ: да, один и тот же URL-адрес за разными ссылками встречается довольно часто. Но то, о чем вы беспокоитесь, не имеет простого ответа, оно полностью основано на желаемом вами UX.

Обратите внимание, что продукты просмотра и продукты редактирования не являются зарегистрированными отношениями ссылок (см. http://www.iana.org/assignments/link-relations/link-relations.xhtml ) для списка, поэтому на самом деле они должны быть URI.

Это важно, потому что очень часто разрешается разыменовывать эти URI/следовательно, URL-адреса, которые фактически содержат документацию о том, что означают отношения ссылок. Таким образом, ваши продукты редактирования превратились в URL-адрес, например http://example.com/rels/edit-products и извлеченные могут привести к документации, указывающей, что можно редактировать.

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

Каждый продукт предположительно является ресурсом, поэтому у него есть собственная ссылка на себя. Если я хочу изменить этот продукт как разработчик, для меня было бы естественно ПОСТАВИТЬ некоторый JSON, представляющий продукт, в ссылку на себя. Мне не нужна ссылка на редактирование, потому что мои намерения ясны с моим запросом. Если я не могу редактировать, я должен получить ответ, указывающий на это (и, если это через http, соответствующий код ответа http). Если я хочу удалить этот продукт, я могу отправить DELETE на URL-адрес собственной ссылки. Если бы я хотел изменить продукт специально, я мог бы использовать запрос PATCH. Если вам нужны более ограниченные возможности редактирования, то отношение ссылки IANA формы редактирования будет хорошим кандидатом, после чего будет возвращена форма, используемая для редактирования ресурса, как предполагает/разрешает служба. И снова вы можете иметь свои собственные отношения URI, которые следуют любым соглашениям, которые вы документируете. Другое соображение, которое вы, кажется, имеете, заключается в том, что вы хотите, чтобы клиент знал, может он или не может редактировать ресурс. Если вы делаете случай редактирования формы, то это так же просто, как наличие или отсутствие этой связи. Вы также можете использовать отношение edit IANA, чтобы указать возможности необработанного редактирования (и оно может иметь тот же URL-адрес, что и self).

Итак, я думаю, что это касается продуктов, давайте поговорим о коллекции.

Идеи редактирования коллекции остаются теми же, даже если вы решили, что каждый продукт не является отдельным ресурсом. Вставка продукта в собственный URL-адрес коллекции будет означать добавление продукта в коллекцию, в то время как вставка коллекции продуктов в собственный URL-адрес заменит всю коллекцию. PATCH изменит коллекцию. Кроме того, если бы у вас были интересные случаи, когда пользователь мог только добавить продукт, но не удалить или изменить их порядок, я бы начал углубляться в пользовательские отношения ссылок. Опять же, наличие отношений может указать клиенту, что можно и что нельзя делать, если вам нужна такая функциональность.

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

{ 
  firstname : "Dave",
  lastname : "Matthews",
  links : [ 
    { rel : "self", href : "http://www.domain.com/sales-rep/dmat1" },
    { rel : "product", href : "http://www.domain.com/product1" },
    { rel : "product", href : "http://www.domain.com/product2" },
    { rel : "product", href : "http://www.domain.com/product3" },
    { rel : "product", href : "http://www.domain.com/product4" }
  ] 
}

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

Не совсем понятно, хотите ли вы, чтобы edit-products возвращал ресурс, используемый для редактирования продуктов (например, форму). Я часто нахожу очень полезным думать о моем JSON API так же, как о своем HTML-приложении (веб-сайте), поскольку веб-сайты очень RESTful по своей природе. В приложении, управляемом HTML, это, вероятно, будет иметь место. IE на странице торгового представителя (ресурсе) у вас будет ссылка на страницу (ресурс), которая позволяет пользователю редактировать свои продукты. то же самое просмотр продуктов. В таком случае эти страницы просмотра продукта и редактирования продукта могут быть одним и тем же ресурсом (в IE это одна и та же страница, которая позволяет просматривать и редактировать) или разными ресурсами (в IE две разные страницы, одна только для редактирования, другая только для просмотра). В первом случае у них, вероятно, будет один и тот же URL-адрес, а во втором — разные URL-адреса. Что особенного в RESTful, так это то, что ваше приложение может меняться без изменения его семантики. Сначала вы можете захотеть, чтобы они были отдельными страницами, одна для просмотра, другая для редактирования, поэтому это разные URL-адреса, но затем вы можете передумать и решить, что одна страница подходит для обоих. теперь два отношения ссылок имеют один и тот же URL-адрес, но любой пользовательский интерфейс, построенный поверх этих отношений, по-прежнему работает правильно и переводит пользователя на нужный ресурс.

Есть еще один вариант (каламбур), который у вас есть, и он должен отправить запрос OPTIONS на собственный URL-адрес. Это должно предоставить запрашивающему пользователю методы http, такие как PATCH, PUT, POST, DELETE и т. д. Из этого набора параметров вы можете создать пользовательский интерфейс, обеспечивающий правильные элементы управления пользовательским интерфейсом. К сожалению, это требует дополнительного обращения к серверу, но это очень удобный механизм для определения разрешенных возможностей текущего клиента.

На этом я поднимаю самый важный момент. Как правило, метод запроса (и запрос в целом) подразумевает намерение клиента (обновить, удалить, добавить, сбросить, исправить и т. д.), и служба должна интерпретировать это намерение (а также задокументировать возможные намерения) и решить, что делать. выполнить просьбу или нет. При таком подходе и запросе OPTIONS вам, как правило, не нужно ничего, кроме SELF связывать отношения иерархии (например, продукты) для простого приложения CRUD.

person Chris DaMour    schedule 08.07.2015
comment
Я немного потерял ссылку на форму редактирования. Это означает, что я должен создать ресурс под названием /sales-rep/bob/products/edit-form. Не знаете, как именно должна выглядеть форма редактирования? PUT для /products выглядит лучше, но я могу что-то упустить? - person mogronalol; 08.07.2015
comment
HTML-форма — отличный целевой ресурс для формы редактирования. Есть другие стандарты для форм. - person Chris DaMour; 08.07.2015
comment
Хотя я согласен с большей частью поста, у меня есть серьезные проблемы с двумя пунктами, перечисленными здесь. Во-первых, вы предполагаете, что клиент уже знает, что сервер ожидает в качестве входных данных (сильная связь?!), поэтому вы можете напрямую использовать PUT, POST, ... на определенной конечной точке вместо запроса ресурса, который учит вас тому, что нужно серверу. . edit-form делает именно это. Второй вопрос, который меня беспокоит, связан с этим предложением: A PUT of a product to the collection's self url would imply adding a product to the collection Правда? Согласно RFC 7231 он должен заменить содержимое коллекции данными о продукте. - person Roman Vottner; 04.12.2019
comment
вы говорите, форма редактирования, я говорю, используйте URL-адрес отношения ссылки, чтобы получить некоторую информацию о том, как построить вещь... или ссылку на профиль. но да, конечно, форма редактирования тоже работает, просто это не мое предпочтение. что касается размещения ... если вы ПОМЕЩАЕТЕ коллекцию в href коллекции, она заменяет коллекцию, но если вы РАЗМЕЩАЕТЕ продукт в href коллекции, я думаю, что цель состоит в том, чтобы добавить продукт. Но я бы все это описал в rel docs. Вы также можете просто не сказать: «Эй, я ожидаю, что вы разместите коллекцию, я не знаю, что делать только с продуктом!» но мне нравится делать мои услуги более щадящими - person Chris DaMour; 05.12.2019