Должны ли вложенные отношения отражаться в URL-адресах для JSON API?

Я пытаюсь следовать JSON API. Мне нужно предоставить CRUD-доступ к вложенному ресурсу: обзоры продуктов.

до использования JSON API я ожидал бы такой интерфейс REST:

GET    /products/:product_id/reviews     - list reviews for a product
POST   /products/:product_id/reviews     - add a review for a product
PATCH  /products/:product_id/reviews/:id - update a review for a product
DELETE /products/:product_id/reviews/:id - delete a review for a product

Я вижу некоторые упоминания о вложенной структуре, как это в спецификации:

например, URL для комментариев к фотографии будет:

/photos/1/comments

но я не уверен, что это структура предназначена для всех действий.

С одной стороны, POST /products/:product_id/reviews для создания кажется избыточным, если я собираюсь указать продукт в теле POST, в разделе данных обзора relationships.

С другой стороны, если полезно указать идентификатор продукта при удалении обзора (возможно, это не так),DELETE /products/:product_id/reviews/:id кажется, единственный разумный способ сделать это;люди спорят о том, разрешено ли тело запроса даже для запросов удаления.

я мог бы гнездиться для некоторые запросы, а не другие:

GET    /products/:product_id/reviews  - list reviews for a product
POST   /products/:product_id/reviews  - add a review for a product
PATCH  /reviews/:id                   - update a review
DELETE /reviews/:id                   - delete a review

но это, кажется, странно противоречивы.

Я никогда не мог гнездо:

GET    /reviews     - list reviews for the product specified in params
POST   /reviews     - add a review for the product specified in params
PATCH  /reviews/:id - update a review
DELETE /reviews/:id - delete a review

но это кажется неудобным и, похоже, не соответствует первой цитате, которую я сделал из документов.

должны ли вложенные отношения ресурсов отражаться в URL-адресе при использовании JSON API?

2 ответов


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

Я использую JSON API чуть более года в производственной системе, и я хотел бы дать свои два цента.

сначала, когда я начал проект, который собирался использовать JSON API, я сомневался в вложенных и не вложенных ресурсах. Затем я столкнулся с проблемами с вложенными ресурсами, которых можно было бы избежать с не вложенными ресурсы.

взять те же пути, как в вашем примере, рассмотрим!--0--> конечной точки. Когда это сделано, имеет смысл вложить отзыв в продукт, потому что мы изначально показываем отзывы в контексте продукта. Все хорошо.

затем мы хотим создать страницу в интерфейсе, которая показывает пользователя и все отзывы, которые пользователь написал. Хотя у нас уже есть конечная точка для получения отзывов, нам придется построить новую, например GET /users/:id/reviews.

если бы мы просто поставили первую конечную точку на GET /reviews фильтр ?filter[product_id]=:id, мы могли бы просто добавить новый фильтр к этой конечной точке, что имеет смысл IMO.

я использую вложенные ресурсы, но только для одноэлементных ресурсов, таких как GET /users/:id/email_settings и несколько других особых случаев, когда это имеет смысл.

по моему опыту, это облегчает в будущем, если каждый ресурс считается независимым от других ресурсов. Существуют ресурсы и отношения между ресурсами. Ни один ресурс не" владеет " другим ресурсом в контексте API (в контексте бизнес-логики это другая история).

я работал с этой стратегией, и меня все еще удивляет, насколько хорошо она работает при добавлении новых функций к существующим конечным точкам и при добавлении новых конечных точек.


Если вы пришли из лагеря CQRS, вы поймете, почему дизайн Restful API иногда неудобно. Это неудобно, потому что, естественно, действия запроса (GET) и действия мутации (POST, PATCH, DELETE) должны говорить на двух разных языках. Действия запроса естественно ориентированы на отношения и богаты данными; в то время как действия мутации нет. Поэтому легко использовать вложенный URL для обхода между сущностями отношений. Но мутация вы должны предоставить достаточно информации для выполнения задач. Иногда это излишне как ваш пример Post. Иногда отсутствует, как ваш пример удаления. Иногда у вас есть задача, требующая много ресурсов; вы не знаете, куда вкладывать.

вы должны проверить Facebook Graph API или Azure Graph API, они столкнулись с теми же проблемами и имеют некоторые хорошие решения. Важно, чтобы вы следовали последовательному дизайну. Некоторые правила:

  • удалить, всегда обновлять для прямого ресурса.
  • POST use с вложенным ресурсом, если вы хотите создать как объект, так и основные отношения. Второстепенные отношения следует вкладывать в тело. Если у вас есть два равных отношения, рассмотрите оба вложенных API.
  • используйте сообщение против поддельного ресурса для задач, связанных со многими ресурсами.

    сообщение / transferfund

  • использование POST против поддельных отношений для задач не может соответствовать никаким http-глаголам. Например, вы хотите иметь тело для действия удаления, используйте

    сообщение / ресурс / id / deleteItForMe { причина: "Ненавижу это"}