Как структурировать иерархию ресурсов REST?

Я новичок в веб-разработке на стороне сервера и недавно много читал о реализации RESTful API. Один из аспектов REST API, на котором я все еще застрял, — это то, как структурировать иерархию URI, которая идентифицирует ресурсы, с которыми клиент может взаимодействовать. В частности, я застрял в решении, насколько подробной должна быть иерархия и что делать в случае, когда ресурсы состоят из других типов ресурсов.

Вот пример, который, надеюсь, покажет, что я имею в виду. Представьте, что у нас есть веб-сервис, который позволяет пользователям покупать товары у других пользователей. Итак, в этом простом случае есть два ресурса верхнего уровня: пользователи и продукты. Вот как я начал структурировать иерархию URI,

Для пользователей:

/users
      /{id}
           /location
           /about
           /name
           /seller_rating
           /bought
           /sold

Для продуктов:

/products
         /{id}
              /name
              /category
              /description
              /keywords
              /buyer
              /seller

В обоих этих случаях объекты в каждой иерархии ссылаются на подмножество объектов в другой иерархии. Например, /users/{id}/bought — это список продуктов, которые купил какой-либо пользователь, который является подмножеством /products. Кроме того, /products/{id}/seller указывает на пользователя, который продал определенный продукт.

Поскольку эти URI ссылаются на другие объекты или подмножества других объектов, должен ли API поддерживать такие вещи, как: /users/{id}/bought/id/description и /products/{id}/buyer/location? Потому что, если эти типы URI поддерживаются, что может остановить что-то вроде этого /users/{id}/bought/{id}/buyer/bought/{id}/seller/name или чего-то столь же запутанного? Кроме того, в этом случае, как бы вы обработали маршрутизацию, поскольку маршрутизатору на сервере пришлось бы интерпретировать URI произвольной длины?


person martega    schedule 06.03.2013    source источник
comment
См. также Каковы лучшие практики для вложенных ресурсов REST?   -  person Grigory Kislin    schedule 07.09.2019


Ответы (2)


Цель состоит в том, чтобы создать удобные идентификаторы ресурсов, не пытайтесь ссылаться на все подряд. Вам не нужно повторять свои отношения с базой данных в представлении URL :)

Ссылки типа /product/{id}/buyer никогда не должны существовать, потому что для этого ресурса уже есть идентификатор: /user/{id}

Хотя это нормально иметь /product/{id}/buyers-list, потому что список покупателей — это свойство продукта, которое не существует в других контекстах.

person Anri    schedule 08.03.2013
comment
Итак, вы хотите сказать, что каждый ресурс в системе имеет ровно один URI? Потому что так все намного проще. В приведенном выше примере, что бы вы порекомендовали, если бы я хотел выставить продавца какого-то товара через API (у товаров только один продавец)? Должен ли я просто заставить людей сделать GET /products/{id}, который вернет некоторый объект JSON с продавцом в нем? - person martega; 09.03.2013
comment
JSON для /products/{id} может содержать вложенный объект пользователя для вашего удобства или URL-адрес этого пользователя, это ваш выбор, и это не меняет того факта, что оба существуют отдельно. - person Anri; 09.03.2013
comment
Кстати, это помогает взглянуть на API других сервисов. Например: developer.foursquare.com/docs/venues/venues - person Anri; 09.03.2013

Вы должны думать об этом в стиле CRUD, где каждый объект поддерживает создание, чтение, обновление и удаление (обычно с использованием HTTP-глаголов GET, POST, PUT и DELETE соответственно).

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

Пользователи

GET    /users       - Return a list of all users (you may not want to make this publically available)
GET    /users/:id   - Return the user with that id
POST   /users      - Create a new user. Return a 201 Status Code and the newly created id (if you want)
PUT    /users/:id   - Update the user with that id
DELETE /users/:id  - Delete the user with that id

Вдаваться в подробности, например /users/:id/about, скорее всего, не нужно. Хотя это может работать, это может стать немного сверхспецифичным.

Возможно, в вашем случае вы могли бы добавить:

GET    /users/:id/bought - Array of products that the user bought
GET    /users/:id/sold   - Array of products that the user sold

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

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

GET    /products- Return a list of all products
GET    /products/:id   - Return the products with that id
POST   /products- Create a new product. Return a 201 Status Code and the newly created id (if you want)
PUT    /products/:id   - Update the product with that id
DELETE /products/:id  - Delete the product with that id

GET    /products/:id/buyers     - Array of who bought the product
GET    /products/:id/sellers    - Array of everyone selling the product
person Nick Mitchinson    schedule 08.03.2013