REST API design: как обрабатывать ресурсы, которые также могут быть под-ресурсами

Мне нужно поставить службу REST (только для чтения) на существующую базу данных продукта. Легкая часть имеет ресурс продукта верхнего уровня, например:

/api/products/

Теперь фактическим абонентам этой службы скорее потребуется получить соответствующие продукты на основе идентификатора магазина и конкретного процесса (например, "розничная торговля" ). За кулисами сочетание этих двух значений приводит к настроенному подмножеству продуктов. Это должно быть прозрачным для вызывающего, ему не нужно знать об этих "портфелях продуктов".

Итак, я подумал о разработке URI, как это, где 1234 является StoreID, а розничная торговля - это процесс:

/api/stores/1234/retail/products

Первый вопрос, который возникает здесь, заключается в том, следует ли мне возвращать сюда полные продукты или URI для их отдельных ресурсов в /api/products/... pro будет ясно, что вызывающему абоненту не нужно извлекать каждый отдельный продукт из /api/products, будет заключаться в том, что это приведет к кеширующей головной боли в URI/api/stores/1234/retail/products URI.

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

/api/products/ABCD/prices

будет очевидным выбором, но опять же, поскольку StoreID и Process имеют отношение к предварительному фильтру цен, URI вроде:

/api/stores/1234/retail/products/ABCD/prices

будет более уместным.

В то же время существуют другие подресурсы продуктов, которые не имеют смысла иметь под этим URI, например, информацию о продукте. Это явно имеет смысл непосредственно в /api/products/ABCD/details, поскольку они не зависят от хранилища или процесса.

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

/api/products?store=1234&process=retail
/api/products/ABCD/prices?store=1234&process=retail

Более того, процесс или storeid не имеют ничего общего с продуктом, поэтому запрос его непосредственно на продукт кажется странным. Для цен это имело бы смысл, однако.

Итак, мой вопрос: есть ли хороший способ решить эту проблему, которую я не вижу? И: вы порекомендовали бы возвращать полные продукты, когда они являются субресурсами, - и что вы думаете о кешировании обработки (HTTP) при этом?

Ответы

Ответ 1

Первый вопрос, который возникает здесь, - это если я должен вернуть полный продукты здесь или URI для их индивидуальных ресурсов на /api/products/ [...] было бы, что это приведет к кеширующей головной боли в /api/stores/ 1234/retail/products URI.

Я обязательно верну полные продукты - представьте сумму, которую клиент должен был бы сделать, если бы просто хотел отобразить список имен продуктов. В идеале эта конечная точка будет разбита на страницы (например, строка запроса может включать в себя что-то вроде &pageSize=10&pageNumber=2).

Также существуют различные решения для кэширования - например, вы можете кэшировать все продукты в службе структуры данных, например Redis.

Чтобы усложнить ситуацию, эти продукты, конечно, также имеют цены [...] и подробный субресурс.

Глядя на уровень зрелости Ричардсона 3-го уровня, это будет где ссылки вступают в игру, и вы можете иметь что-то вроде этого под продуктом ресурс:

<link rel = "/linkrels/products/ABCD/prices" 
      uri = "/products/ABCD/prices?store=1234&process=retail"/>

и другую аналогичную ссылку для ресурса сведений о продукте.

@Roman прав, REST предназначен для обнаружения, клиенты должны просто следовать ссылкам (которые могут иметь длинный/уродливый uris), вместо того, чтобы их запоминать (например, в SOAP, например).