2013-03-14 4 views
4

Я работаю над REST-ful API, в котором ресурсы, которые довольно взаимосвязаны. Ресурсы ссылаются друг на друга, и эти ссылки могут быть созданы или удалены. Я немного неопределен, как поддерживать объединение ресурсов вместе, когда они ссылаются друг на друга с помощью гиперссылок.Как обрабатывать обновления ресурса REST при использовании гипермедиа-ссылок

Вот простой пример с двумя ресурсами, A и B.

Resource A: 
    name: integer 
    list_b: [list of resource B] 

Resource B: 
    id: integer 
    description: String 

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

Resource A: 
{ 
    id: 1, 
    list_b: [ 
     { id: 1, href: "https://server/api/b/1" }, 
     { id: 2, href: "https://server/api/b/2" } 
    ] 
} 

Если пользователь хочет добавить или удалить одну из ссылок B в список А, то как они делают это, принимая во внимание наличие гиперссылки? Я хочу, чтобы пользователь мог обновить весь ресурс A в одной операции PUT, но ничего на выходе не указывает, какое значение для B требуется. Это имеет смысл для меня пользователю выполнять PUT с содержанием, как это:

Resource A: 
{ 
    id: 1, 
    list_b: [ 
     { id: 1, href: "https://server/api/b/1" }, 
     { id: 2, href: "https://server/api/b/2" }, 
     { id: 3 }, 
    ] 
} 

и получить обновленный ресурс (в ответ), как это:

Resource A: 
{ 
    id: 1, 
    list_b: [ 
     { id: 1, href: "https://server/api/b/1" }, 
     { id: 2, href: "https://server/api/b/2" }, 
     { id: 3, href: "https://server/api/b/3" } 
    ] 
} 

Я беспокоюсь, что пользователь не обязательно будет знать, что включать в ресурс при обновлении ресурса A list_b.

При работе с гиперссылками с одного ресурса на другой, как следует создавать и обновлять работу? Если клиентам разрешено обновлять часть ссылки (id), или им необходимо будет обновить обе части ссылки?

Примечание: Я знаю, что другой подход может быть обнажая вложенную URL для ресурса A. Это может выставить list_b как ресурс, который предназначен через HTTP (что позволяет клиентам использовать POST, PUT и DELETE на ресурсе списка сам). Но это кажется менее разумным, если A содержит несколько ссылок на другие типы ресурсов. Каждое поле, которое ссылается на другое, потенциально требует суб-url, который, если есть 10+ полей, является громоздким и требует нескольких HTTP-запросов для обновления ресурса.

ответ

2

HATEOAS соединяет ресурсы вместе в интерфейсе RESTful, и здесь неясно, действительно ли вспомогательные объекты, которые вы описываете, действительно имеют смысл в качестве независимых ресурсов. «AS» часть HATEOAS напоминает нам о роли, которую веб-страницы играют как «ресурсы» в веб-приложении. Каждая веб-страница представляет собой интерактивное представление состояния приложения («приложение» в этом случае является классическим, многостраничным веб-приложением), а гиперссылки на другие ресурсы предоставляют пользователю переход к другим состояниям приложений.

RESTful Web API, имеющий JavaScript-код, а не человека как своего клиента, естественно ориентирован на доступ к данным, поэтому мало, если какой-либо его ресурс принимает форму «состояние приложения», per se. В традиционном веб-приложении вы можете нарисовать диаграмму перехода состояния и четко увидеть связи между состояниями и, следовательно, среди ресурсов.В RESTful API границы между пассивными ресурсами данных мотивируются большей эффективностью взаимодействия клиент/сервер и другие тонкие силы.

Значит, ваши вспомогательные объекты («B») действительно должны быть представлены в качестве первоклассных ресурсов? Существуют ли случаи, когда передняя часть будет перечислять или иным образом обращаться к ним независимо от агрегатов, в которых они участвуют («А»)?

Если ответ «нет», то они, очевидно, не должны быть представлены гипертекстовым образом в структуре «А». Я полагаю, что ответ «да», однако, и у вас также есть веские основания предлагать все другие вспомогательные объекты, к которым вы относитесь как независимые ресурсы. В этом случае существует некоторый объем работы интерфейса в виде маршрутов и контроллеров, которые необходимы для поддержки всех этих ресурсов независимо от того, что ваше приложение, по-видимому, предоставляет средства для манипулирования ими каждый самостоятельно или, по крайней мере, запрос их (через гиперссылки, например, в вашем примере).

В этом случае POST к пути, представляющему вашу коллекцию объектов «B» (например, «server/api/b»), может возвращать URL-адрес в заголовке «location» заголовка ответа как POST, которые создают новый ресурсы должны делать. Когда ваш пользователь интерактивно добавляет новый «B» в список, принадлежащий «A» на вашей веб-странице, ваш интерфейс может сначала POST нового «B», получив URL-адрес обратно через заголовок местоположения при успешном завершении. Затем он может включить эту ссылку в представление списка внутри своего объекта «A» перед тем, как установить обновленный «A.»,

Значение идентификатора - это немного морщин, так как у вас возникнет соблазн разрушить инкапсуляцию заднего конца, извлекая значение идентификатора из текста URL. Истинные фанатики HATEOAS делают их API RESTful продуцировать запутанные, хэшированные или иным образом непонятные URL-адреса, специально для того, чтобы сорвать такое прерывание инкапсуляции со стороны клиентов. Лучше, чтобы POST нового объекта «B» возвращал полное представление нового объекта «B», включая его идентификатор, в свой корпус ответа, чтобы клиент мог восстановить полный объект и извлечь из него ID, тем самым сужая связь с самим ресурсом, а не с деталями интерфейса RESTful, через который он получен.

+0

Спасибо за ваши мысли. Вы правы в том, что ресурсы, с которыми я работаю, намного сложнее и действительно имеют свою собственную модель использования в качестве первоклассных ресурсов (мой пример, по общему признанию, очень прост). Все создания ресурсов в этом API действительно возвращают URL-адреса в заголовке местоположения, поэтому звучит так, будто вы говорите, что list_b может быть ограничен только содержащимися URL-адресами (без идентификаторов), которые клиент должен иметь в любом случае. Если пользователь хотел добавить существующий ресурс B в этот список, он будет использовать URL-адрес. Это справедливое толкование? – bedwyr

+0

Да, не зная дальнейших подробностей, я бы сказал, что это справедливое толкование. – Jollymorphic

+0

Еще раз спасибо. Так что бы вы выступали за все ссылки на ресурсы в сущности (я знаю, это радикальное обобщение), чтобы быть просто URL-адресом? – bedwyr

1

Вы также должны смотреть на LINK method:

LINK /ResourceA/1 HTTP/1.1 
Link: <http://example.com/ResourceB/3>; rel="list_b" 
... 

204 Yeah Fine, Whatever 

Это говорит/ResourceA/1 для ссылки/ResourceB/3, используя отношения "list_b".

+0

+1 Спасибо за ссылку! Я стараюсь как можно больше придерживаться спецификации ванильного HTTP, а используемая среда не поддерживает метод LINK. Тем не менее интересная идея. – bedwyr

+0

Какая структура? На самом деле, структура, которая не поддерживает имена произвольных методов, не является передовым. Поддерживает ли он [метод 'PATCH'] (http://tools.ietf.org/html/rfc5789), который теперь стандартизирован? –

+0

Я использую фреймворк Java Java в тандеме с сервлетами Tomcat для облегчения запросов. Возможно, у них есть способ указать произвольные имена методов, но я придерживаюсь ванильного HTTP для максимальной поддержки среди клиентов. – bedwyr

Смежные вопросы