REST API设计最佳实践,可在单个调用中进行多次收集

时间:2015-07-01 08:18:09

标签: rest

我有2个资源/users/products,我可以使用/users/{id}/products检索用户产品。这很简单,我会返回这样的JSON响应:

{
   "items": {
      ...
   }
}

现在如果我想同时获取user及其products该怎么办?我知道我可以在?expand=products调用上使用/users/{id}并返回如下数据:

{
   "item": {
      ...
      "products": {
          ...
      }
   }
}

但这是最佳做法吗?或者返回这样的东西更好:

{
   "user": {
      "item": {
         ...
      }
   }
   "products": {
      "items": {
         ...
      }
   }
}

所以我的问题是:

  1. 在一次通话中返回多个数据集合的最佳做法是什么?
  2. 我知道减少您正在进行的API调用的数量会更好,但如果我的应用程序在某个时间点需要大量信息,例如userproductscurrencies等。更好的做法是使用各自的api端点并进行多次调用或创建一个端点,在一次调用中返回所有数据?

3 个答案:

答案 0 :(得分:3)

听起来像/users/{id}/products/users/{id}?expand=products是相同的,所以我坚持使用第一个(非查询字符串)来保持您的网址一致。然后以以下格式返回数据:

{
    username: "Dave",
    userid: 123,
    products: [
        {
            productname: "amazing product",
            productid: "ab123"
        }
    ]
}

用户的产品显然是用户的子数据

对于问题2,我应该使用多个端点还是只使用一个,您可以根据您构建该资源的方式进行调用(如果它已被很好地编入索引/缓存,则可能会“更便宜” ),是否存在安全风险,实际使用的每件物品中有多少等。

答案 1 :(得分:1)

包含其他数据的常用方法是这样的(你的第二个例子):

{
    "users: [
        {
            ...
            "products": [
                {
                    ...
                }
            ]
        }
    ]
}

如果您通常将结果包装在“items”-container中,我只会为用户执行此操作,但已将两者都包装在容器中。我认为没有真正的共识,但我会倾向于第一个。作为旁注,因为你在问题中提到它我不会在“item”/“items”之间切换,因为这会破坏为你的数据设置通用容器的目的。而是始终使用项目,如果您只有一个项目将其作为数组返回。

是否应包含项目取决于。因为对于所包含的项目进行分页是不可行的,所以我倾向于不允许包括在什么时候可能会返回很多项目。对于您的示例(用户拥有的产品),如果它意味着来自供应商的产品(例如在目录中),我可能不会使用它,但如果它是某种购物车,那对我来说也没问题。

答案 2 :(得分:0)

我认为您的问题的答案可能是在与您引用的视频(http://www.slideshare.net/stormpath/elegant-rest-design-webinar)相关联的幻灯片共享的75到75张幻灯片中。

我相信在这种情况下另一个好的(类似的)方法是定义更高级别的复合资源(例如' account',' userProducts'等),其中包含您需要的两个子资源,有点像它们的容器。例如:

{
    "account" : {
       "id" : "123",
       "user": {
          "items": {
             ...
          }
       }
       "products": {
          "items": {
             ...
          }
       }
    }
}

他们做了类似于你在幻灯片中看到的东西,他们创建了容器'资源,但不是嵌入集合数据,而是提供指向各个集合的链接。

但我不确定多个集合最适合您提供的示例。在您的情况下,我认为从/ users / {id} / products返回整个产品列表并简单地标记该用户实际拥有的产品列表可能是适当的(将非所有者解释为可用于那个用户),例如:

{
    "user" : {
       "id" : "123",
       "products": [{
          "id" : "A456",
          "owns" : true,
          "details": {
             ...
          }
       }]
    }
}

您甚至可能希望控制是否拥有“非拥有”'项目显示在结果中,例如:

/users/{id}/products?ownership=all

换句话说,"给我给定用户可用的产品清单,并标记他们实际拥有的产品。"

/users/{id}/products?ownership=owned

同样,"只给我给定用户实际拥有的产品。"

在面向资源的REST架构风格中,查询参数适用于选择(也就是搜索;哪些行),分页(多少),排序(哪个顺序)和投影(哪些列)。

'所有权'查询参数适合选择/搜索类别。