在REST调用中返回多个资源

时间:2018-11-28 09:53:58

标签: rest api django-rest-framework

我正在提供对REST端点的访问权限,其中计算了一些聚合。 假设模型如下:

购买:

  • 金额:支出金额
  • group:电子,食品,家具,...之一...
  • 日期:购买日期

现在,我想提供一个购买时间表,每周汇总一次,并按组划分。这将产生以下数据:

{
  "ELECTRONICS": [{"week": "2018WK1", "amount": 1000.0}, ...],
  "FOOD": [{"week": "2018WK1", "amount": 2000.0}, ...],
  "FURNITURE": [{"week": "2018WK1", "amount": 3000.0}, ...],
  ...
}

一些注意事项:

  • 事先不知道组数(取决于存储的数据)
  • 由于这是计算数据,因此我想在一个请求中返回整个内容,而不必在单独的请求中为每个组进行汇总

请求的URL类似于:/api/weekly_purchases/2018

如何在REST API中提供此类资源?

2 个答案:

答案 0 :(得分:2)

  

在REST调用中返回多个资源

您如何将其作为网页?

您网站上的某个地方将是一个链接,其中包含文本“本周的摘要”(或您所在域语言中的任何适当概念)。如果用户单击该链接,浏览器将在一个URL上执行GET,该URL将转到服务器,将所有数据聚合在一起,然后返回结果。

是吗?

REST并不关心URI的拼写(浏览器不会尝试解释 URL,除非使用非常浅泛的通用方式),因此from osgeo import osr很好

诀窍是要认识到,按周细分的总结当前会计年度购买报告的报告是一种资源。它可能包含的数据可以复制其他资源中的信息,甚至可以复制许多其他资源中的数据,但是它本身仍然是资源。

答案 1 :(得分:1)

正如我在最初的评论中或VoiceOfUnreason所提到的,适用于基于浏览器的Web的相同技术适用于遵循REST体系结构原理的应用程序所使用的任何交互模型。如VoiceOfUnreason所述,客户端最初会请求从入口点返回的某种状态,即https://api.acme.com,该状态将返回客户端可以用来执行其任务的链接的集合。为了让客户端确定要调用的URL,响应应该给URI一个有意义的名称(链接关系名称)。 IANA维护a list of already specified link-relation names,如果可能,应该使用,或者在其他标准中定义自己的一个。根据{{​​3}},在开发RESTful架构时,媒体类型和链接关系的规范是最重要的事情之一。

为简单起见,我在整个示例中使用简化的Fielding语法。

{
  ...
  "_links": {
    "self": {
      "href": "https://api.acme.com"
    },
    ...
    "archives": {
      "href": "https://api.acme.com/weekly_purchases"
    },
    ...
  }
}

根据HAL-JSON archives

  

表示所引用的文档描述了具有历史意义的记录,文档或其他材料的集合

因此,链接关系名称描述了URI的意图,如果有兴趣检索历史条目的集合,客户端可以使用该URI。客户端实际上并不需要知道确切的URI,因为他只需遵循链接关系的目标href元素就可以了解它。这样,服务器可以随时更改其内部URI结构,而无需实际破坏客户端。

在遵循archives目标URI时,客户端将不会真正知道必须如何检索实际数据,因为URI和链接关系名称是通用的。但是服务器将指导客户端完成其任务。对上述目标URI的调用的响应可能返回以下内容:

{
  "year": [
    "2018":  {
      "_links": {
        "chapter": {
          "href": "https://api.acme.com/weekly_purchases/2018"
        }
      }
    },
    "2017": {
      "_links": {
        "chapter": {
          "href": "https://api.acme.com/weekly_purchases/2017"
        }
      }
    },
    ...
    "2014": {
      "_links": {
        "chapter": {
          "href": "https://api.acme.com/weekly_purchases/2014"
        }
      }
    }
  ],
  "_links": {
    "self": {
      "href": "https://api.acme.com/weekly_purchases"
    },
    "first": {
      "href": "https://api.acme.com/weekly_purchases"
    },
    "next": {
      "href": "https://api.acme.com/weekly_purchases?p=1"
    },
    "last": {
      "href": "https://api.acme.com/weekly_purchases?p=3"
    },
    "current": {
      "href": "https://api.acme.com/weekly_purchases"
    }
  }
}

此响应基本上仅告诉客户有很多可用的年份可供选择,并且客户必须决定自己对调用URI感兴趣的年份以继续执行其任务。 nextlastfirst链接关系表明有多个页面可用,因为每页仅返回5年。 current链接关系名称将始终指向集合中的最新条目,这是集合资源的初始页面(或首页)。请进一步注意,多个不同的链接关系名称如何指向相同的URI。有时并不清楚使用哪个链接关系名称,因为它们的语义部分重叠。这只是链接关系名称可以完成的示例。

客户现在可以通过遵循2018年的章节链接来进一步细分到2018年的购买。现在,调用URI的响应可能看起来像这样:

{
  "purchase": [
    "W1": {
      "sum": 1263.59,
      "currency": "Euro",
      "_links": {
        "about": {
          "href": "https://api.acme.com/weekly_purchases/2018/1"
        }
      }
    },
    "W2": {
      "sum": 569.32,
      "currency": "Euro",
      "_links": {
        "about": {
          "href": "https://api.acme.com/weekly_purchases/2018/2"
        }
      }
    },
    ...
    "W48": {
      "sum": 72.98,
      "currency": "Euro",
      "_links": {
        "about": {
          "href": "https://api.acme.com/weekly_purchases/2018/48"
        }
      }
    },
    "current": {
      "sum": 72.98,
      "currency": "Euro",
      "_links": {
        "about": {
          "href": "https://api.acme.com/weekly_purchases/2018/48"
        }
      }
    }
  ],
  "_links": {
    "index": {
      "href": "https://api.acme.com/weekly_purchases"
    },
    "self": {
      "href": "https://api.acme.com/weekly_purchases/2018"
    },
    "current": {
      "href": "https://api.acme.com/weekly_purchases/2018"
    },
    "prev": {
      "href": "https://api.acme.com/weekly_purchases/2017"
    },
    "prev-archive": {
      "href": "https://api.acme.com/weekly_purchases/2017"
    },
    "first": {
      "href": "https://api.acme.com/weekly_purchases/2000"
    }
  }
}

只有在客户对此类详细信息真正感兴趣的情况下,您才可以在每周摘要中添加内容,也可以通过单击About链接将其隐藏起来。

请进一步注意:由于weekly_purchases只是一个字符串,对客户端没有任何意义,因此它并不真正了解其含义。因此,您也可以将其重命名为purchase-archive或类似的名称,然后向客户介绍其他选择,让客户确定是否要该年的每周,每月或总计。

REST旨在为客户提供选择,并告诉其实际选择的目的。 RESTful架构试图解决的目标之一是客户端和服务器之间的严格耦合,以防止后者和服务器自由发展,而如果后者发生意外更改,则前者将崩溃。仅当使用某些标准来增加互操作性的可能性时,这种去耦才有效。通常,带外信息(有关API以及如何与之交互的现有知识)导致耦合。甚至HTML 5 spec都说,虽然需要一些先验知识,但不是直接编码到应用程序中,而是重用某些标准,例如定义良好且稳定的媒体类型和链接关系名称。