Когда использовать вложенные ресурсы в RESTful API

16

У меня есть два ресурса: пользователи и ссылки.

Пользователи могут иметь несколько ссылок, связанных с ними. Я разработал мой RESTful API, чтобы вы могли получить доступ к ссылкам, связанным с пользователем, по следующему URI:

/users/:id/links

Однако мне всегда нужно иметь URI только для ссылок - иногда мне могут понадобиться все ссылки независимо от пользователя.

Для этого у меня есть:

/links

Это звучит нормально? Наличие двух URI для ссылок?

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

/links/user/:id или /links/?user=:id

Таким образом, у меня есть только один ресурс для ссылок.

Оливер Джозеф Эш
источник
3
хм .. Это кажется более элегантным:/links/user/:id
theMarceloR
7
@theMarceloR: Это единственный пример из трех, который мне не очень понятен. Это ресурс для ссылки или для пользователя? URI гораздо менее неоднозначен, если использовать метод вложенных ресурсов ( /users/:id/links) или метод строки запроса ( /links/?user=:id), поскольку на самом деле это запрос. /links/user/:idможет выглядеть красиво и / или быть проще в некоторых фреймворках, но на самом деле это довольно запутанно.
Aaronaught

Ответы:

16

Нет, нет ничего плохого в наличии нескольких ресурсов для одной и той же «вещи», в данном случае это списки ссылок.

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

/links -- all links
/links/:linkid -- a particular link

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

/links?user=/users/:userid

Это также позволяет упростить состав фильтров:

/links?user=/users/10&since=2013-01-01

И это легко понять концептуально - у вас есть набор предметов, и вы добавляете в него фильтры.

При этом нет ничего более «RESTful» в этом подходе, чем любая другая схема именования URI. Это просто соглашение, которое мы нашли понятным человеку, и нам, разработчикам, легко понять и принять его. REST не заботится о том, что вы указали в идентификаторах ресурсов.

свиристель
источник
1
«Все ресурсы, в которых нет строгого владения, чтобы не быть вложенными», звучит как хорошее правило. Огромное спасибо.
Оливер Джозеф Эш
5
Я бы сказал , что там есть что - то неправильно с наличием нескольких ресурсов для того же физического лица, но это не на самом деле , что это такое. Каждая отдельная ссылка имеет канонический URL (links /: id), тогда как каждый из вышеперечисленных ресурсов фактически является одним ресурсом (/ links) с примененными фильтрами. Кроме того, меня уволила ?user=users/:useridстрока в запросе; что не так с просто ?userid=:userid?
Aaronaught
2
@Aaronaught: причина придерживаться URI вместо голых идентификаторов заключается в том, что клиенты могут одинаково обрабатывать все идентификаторы ресурсов, то есть клиенту нужно только знать, что «этот пользователь идентифицирован "/*******"; где *непрозрачные. но тот же самый идентификатор всегда можно использовать для ссылки на этот ресурс (например, со ссылками), для получения самой последней версии этого ресурса и так далее. содержимое этого URI понимается только сервером происхождения. Это также означает, что если нужно изменить идентификаторы, скажем /realm/:businessid/users/:id, клиент вообще не меняется.
SingleNegationElimination
@TokenMacGuy: Извините, я не понимаю ни одной части вашего комментария. В чем практическая разница между /users/:userid/linksи /links?userid=:userid? В обоих случаях идентификаторы не меняются, они выбирают текущую версию этого ресурса, и клиент обрабатывает их одинаково. Канонического URL для этого не существует, потому что это не ресурс, а запрос, так что это всего лишь два разных типа синтаксиса запроса. Мне также не ясно, как клиенту не нужно будет меняться, если структура URL меняется; это считается серьезным изменением в REST, если только не установлен 301.
Aaronaught
1
@Aaronaught: Возможно, я неправильно понял вашу озабоченность. Предположим, /linksподдерживает интерфейс запросов, /links?user=/users/123разрешает подход черного ящика к идентификаторам ресурсов в клиентах, /links?userid=123который не поддерживает. последнее требует от клиента понимания, что такое идентификатор пользователя и как его получить, по-видимому, из ресурса, полученного из /users/123или /links/456/user. Первый означает, что клиент может использовать URI без изменений; Предположим, что /links/.../userдает ответ гипермедиа (скажем, с Location:заголовками).
SingleNegationElimination
1

Так что меня беспокоит: / users /: userid / links возвращает «links», НО, если user_id не идентифицирован, это должно вернуть 404.

тем не мение

/ links? userid =: userid потенциально мог бы вернуть пустой список (по сути, 200), что на самом деле, вероятно, ошибка. И вполне возможно.

Несмотря на то, что оба работают, вложение дает вам дополнительные функциональные возможности, которые вы можете использовать позже.

Ричард Браун
источник