【问题标题】:How to deal with a REST API returning object instead of array for collection in AngularJS?如何处理 REST API 返回对象而不是 AngularJS 中的集合?
【发布时间】:2016-06-06 02:01:30
【问题描述】:

我正在使用的后端团队实现了一个 REST API,它将集合作为对象(而不是数组)返回。 例如,调用 GET /some_resources 将返回:

{
  id_1: {
          p1: "lorem",
          p2: 4 
        }, 
  id_2: {
          p1: "ipsum", 
          p2: 2
        }, 
  id_n: {
          p1: "sic", 
          p2: 7
        }
}

此结构仅限于在 Angular 中使用,因为您无法利用 ng-repeat 指令(例如 orderBy and filter do not work with object)。

对于前面的示例,理想情况下,我宁愿期待一个对象数组:

[ 
  {id: "id_1", p1: "lorem", p2: 4},
  {id: "id_2", p1: "ipsum", p2: 2},
  {id: "id_n", p1: "sic", p2: 7}
]

这将允许直接使用 ngResource 服务返回的对象并将其发送回去,而无需触及其结构。它还允许充分使用 ng-repeat 指令。

当我要求后端团队将他们的集合响应结构从对象更改为数组时,他们认为 API 使用者不应主导响应结构的设计。

我部分同意他们的论点,所以目前,我找到的唯一解决方案是将对象转换为数组,将此对象处理到我的范围内,然后将数组重新转换回原始对象结构,然后再将其发送回到 API。

这导致了很多代码样板,我想知道是否有一种“角度方式”来处理这种情况。

【问题讨论】:

  • 如果您使用 ngResource,您可以设置请求和响应转换器以透明地处理数据操作
  • 好的,我明白了。但是我必须为每种情况实施变压器,对吗?我的意思是,没有通用的方法吗?不过,Transformers 很有趣,因为它们减少了我的控制器中的代码量,这些控制器目前正在执行转换。
  • 如果您所做的只是转换为数组并将对象键添加为id,则可以重复使用转换器
  • 是的,除了在某些情况下,有几个嵌套级别,例如 { id_1: { nested_collection: { key_1: "...", key_2: "..." }, id_2: { key_1:“...”,key_2:“...”}}。在其他情况下,它就像我的问题中的示例一样简单。不过我重用了一些通用代码。

标签: angularjs rest


【解决方案1】:

“他们认为 API 使用者不应主导响应结构的设计”

反驳 - 如果 API 的唯一使用者当前是前端,那么他们有时间在添加其他使用者之前将其放入正确的格式。该数据非常适合作为数组而不是对象。我不知道您的数据集可能有多大,但您将来不想做的一件事是在前端操作对象(无论大小)。浏览器的资源有限,服务器总是可以添加资源。

【讨论】:

  • "如果 API 的唯一消费者当前是前端"。不幸的是(对我来说)不是这样。
【解决方案2】:

Angular JS 的 ng-repeat 不适用于对象,集合应该是数组。

您的 API 团队错了,如果他们没有按照社区使用和创建的方式实现 RESTful API,他们就没有构建 RESTful API。 API 应该为消费者的利益而构建,它是一个接口,就像 UI 是为用户构建的一样。

你说它应该是一个数组而不是一个对象是对的。这是设计由专家社区构建的 API 的一种方法:ebook

已经有很多库可以很好地使用 RESTful API,如果您的后端不能正确实现 API,您将无法使用社区创建的那些出色的库。此外,您未来的消费者将很难使用 API,并且会避免将您的产品用作第三方应用程序

【讨论】:

  • 您的 API 团队错了,他们没有构建 RESTful API”。据WHO称 ?老实说,这是我反对他们的那种论点。但他们的回应是,他们没有发现任何提及不应返回对象而不是数组进行收集的内容。他们的观点是正确的,Angular 在那种情况下表现不佳,但你不会(在网络或文献中)找到一些东西,说你应该更喜欢数组而不是对象。
  • @Mic 他们返回的是一个序列化的Map,它不是一个Collection。他们应该返回一个数组
  • @Phil 再次,这只是一个意见。他们应该返回一个数组,因为 Angular 和其他框架以这种方式工作。但也许,随着 ES6 带来 Map 对象,未来的框架将使用 Map over Array。
  • @Mic,我同意,大多数流行的 API 返回一个 getAll 数组,(github、facebook、twitter)虽然其中一些返回一个对象,但其中的项目列表本身仍然是一个数组,另外,ASP.net 的 Web API 默认返回一个对象列表以获取所有,我不确定其他框架,但我敢打赌它会相似
  • 我同意在@phil 评论中“他们应该返回一个数组”是一种观点,但是关于 Map VS a Collection 的观点是正确的。
【解决方案3】:

更新

let resource = {
  id_1: {
          p1: "lorem",
          p2: 4 
        }, 
  id_2: {
          p1: "ipsum", 
          p2: 2
        }, 
  id_n: {
          p1: "sic", 
          p2: 7
        }
}
let model = [];

Object.keys(resource).forEach(
    key=>{
        let o = resource[key];
        o['id'] = key;
        model.push(o)
    }
);

将其应用于您的资源后,输出将是一个数组,其中包含符合您首选格式的键 idp1p2。使用完模型后,您可以将其恢复为原始格式:

let original={};
model.forEach(o => original[o.id] = {p1:o.p1, p2:o.p2});

原答案

我不知道“Angular 方式”。我使用下面的代码来处理类似的情况。这是打字稿,但可以很容易地适应 javascript。它的灵感来自大卫Sherret's code

getObjValues(e: any) {
    return Object.keys(e).map(k => e[k]);
}

let resource = {
  id_1: {
          p1: "lorem",
          p2: 4 
        }, 
  id_2: {
          p1: "ipsum", 
          p2: 2
        }, 
  id_n: {
          p1: "sic", 
          p2: 7
        }
}

let model = getObjValues(resource)

model 将是一个元素数组,键为 p1p2。如果您需要恢复原始对象,则需要更多代码来保存初始 id_1id_2 并重建原始对象。

【讨论】:

  • OP 也需要id
  • @Patrick,澄清一下,我不是在问如何实现转换 obj 数组。我在问,像 Angular 这样的框架(或使用它的社区)如何建议处理这种情况(使用对象而不是数组来收集)。
【解决方案4】:

如果您的用例非常简单(如果数组中对象的顺序无关紧要),您可以使用 ng-repeat 迭代对象键 according to the docs

<div ng-repeat="(id, value) in myObj"> 
    {{id}} - {{value.p1}} - {{value.p2}} 
</div>

【讨论】:

  • 不,就像我说的,我想利用 ng-repeat 的所有功能,尤其是 orderBy 和 filter 过滤器。拥有一个对象不允许我这样做,因此有必要将其转换为数组。
猜你喜欢
  • 2020-07-23
  • 1970-01-01
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 2018-01-17
  • 2018-12-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多