如何构建 REST 资源层次结构?

Posted

技术标签:

【中文标题】如何构建 REST 资源层次结构?【英文标题】:How to structure REST resource hierarchy? 【发布时间】:2013-02-21 23:33:27 【问题描述】:

我是服务器端 Web 开发的新手,最近我阅读了很多关于实现 RESTful API 的内容。我仍然坚持的 REST API 的一个方面是如何构建标识客户端可以与之交互的资源的 URI 层次结构。具体来说,我一直在决定层次结构的详细程度以及在资源由其他资源类型组成的情况下该怎么做。

这里有一个例子,希望能说明我的意思。想象一下,我们有一个 Web 服务,可以让用户从其他用户那里购买产品。所以在这个简单的例子中,有两个***资源usersproducts。下面是我开始构建 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,您将如何处理路由?

【问题讨论】:

另见What are best practices for REST nested resources? 【参考方案1】:

目标是构建方便的资源标识符,不要尝试交叉引用所有内容。您不必在 URL 表示中重复您的数据库关系 :)

/product/id/buyer 之类的链接永远不应该存在,因为该资源已经存在标识符:/user/id

虽然可以使用/product/id/buyers-list,因为买家列表是产品的属性,在其他情况下不存在。

【讨论】:

那么,您的意思是系统中的每个资源都只有一个 URI?因为这让一切变得简单多了。在上面的例子中,如果我想通过 api 暴露某个产品的卖家(产品只有一个卖家),你会推荐什么?我是否应该让人们执行 GET /products/id 这将返回一些带有卖家的 JSON 对象? /products/id 的 JSON 可能包含嵌套用户对象以方便您或该用户的 url,这是您的选择,它不会改变两者分开存在的事实。 顺便说一句,它有助于查看其他服务的 API。例如:developer.foursquare.com/docs/venues/venues【参考方案2】:

您应该以 CRUD 方式来考虑它,其中每个实体都支持创建、读取、更新和删除(通常分别使用 GET、POST、PUT 和 DELETE HTTP 动词)。

这意味着您的端点通常只会深入一层。比如

用户

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

您可以在其中返回 id 列表(可以通过 products API 获取),或者如果您愿意,您可以在发回之前填充 Products。如果您确实选择填充它们,那么您可能不应该填充每个产品引用的用户。这将导致循环包含并且是错误的。

对于产品,在您的情况下,我会使用:

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

【讨论】:

以上是关于如何构建 REST 资源层次结构?的主要内容,如果未能解决你的问题,请参考以下文章

构建RESTful服务(使用Spring Data JPA)

如何使用 Stargate REST API 在 HBase 中构建更复杂的过滤器层次结构?

如何为 REST API 构建 Mongo 数据库 [关闭]

如何确保资源被释放,嵌套对象层次结构?

如何构建一个 REST API,该 API 采用资源 id 的数组

如何在解决方案资源管理器上保留源文件夹层次结构?