Redux normalizr - 嵌套的API响应

8

我该如何使用normalizr处理嵌套的经过标准化的JSON API响应,这些响应通过{ data: ... }标准进行键控?

例如一个Book

{
    data: {
        title: 'Lord of the Rings',
        pages: 9250,
        publisher: {
            data:  {
                name: 'HarperCollins LLC',
                address: 'Big building next to the river',
                city: 'Amsterdam'
            },
        },
        author: {
            data: {
                name: 'J.R.R Tolkien',
                country: 'UK',
                age: 124,
            }
        }
    }
}   

如何设计模式来处理嵌套的数据键?

你发布的json不符合JSONAPI规范。简而言之,你不能将其他资源嵌套在主要资源中,但是如果想要在有效载荷中包含其他资源,必须使用特定的键include。在主要资源中,您只能发送有关其与其他资源之间关系的一组有限信息,这些信息位于键relationships下。 - NickGnd
好的,我会更新问题。 - AndrewMcLagan
2个回答

6

对于响应中的每个实体,您应该创建自己的模式。

在您的示例中,我们有三个实体 - booksauthorspublishers

// schemas.js
import { Schema } from 'normalizr';

const bookSchema = new Schema('book');
const publisherSchema = new Schema('publisher');
const authorSchema = new Schema('author');

如果某个实体包含需要规范化的嵌套数据,我们需要使用其模式的define方法。该方法接受一个带有嵌套规则的对象。

如果我们需要规范化book实体的publisherauthor属性,我们应该将一个与响应结构相同的对象传递给define函数:

// schemas.js
bookSchema.define({
  data: {
    publisher: publisherSchema,
    author: authorSchema
  }
});

现在我们可以对响应进行规范化处理:
import { normalize } from 'normalizr';
import { bookSchema } from './schemas.js';

const response = {
    data: {
        title: 'Lord of the Rings',
        pages: 9250,
        publisher: {
            data:  {
                name: 'HarperCollins LLC',
                address: 'Big building next to the river',
                city: 'Amsterdam'
            },
        },
        author: {
            data: {
                name: 'J.R.R Tolkien',
                country: 'UK',
                age: 124,
            }
        }
    }
}

const data = normalize(response, bookSchema);

好的,如果您能详细说明一下就太好了。希望您能为社区中的其他人提供一个清晰明了的答案。 - AndrewMcLagan
@AndrewMcLagan 没问题 :) 已更新答案。 - 1ven
如果(如上所述),根响应对象 book 在此情况下也嵌套了 { data },那该怎么办? - AndrewMcLagan

3
我相信您需要使用assignEntity函数,该函数可以在normalize的选项中传递。在这种情况下,如果合适,它让我们过滤掉冗余的data属性并直接转到其中的值。
实际上,assignEntity功能可以让您控制如何规范化每个数据键。在此处可以了解更多信息。
我将其组合为演示,请查看:http://requirebin.com/?gist=b7d89679202a202d72c7eee24f5408b6。以下是代码片段:
book.define({
  data: {
    publisher: publisher,
    author: author,
    characters: normalizr.arrayOf(character)
  }}
);

publisher.define({
  data: {
    country: country
  }
});

const result = normalizr.normalize(response, book, { assignEntity: function (output, key, value, input) {
  if (key === 'data') {
    Object.keys(value).forEach(function(d){
      output[d] = value[d];
    })
  } else {
    output[key] = value;
  }
}});

特别是在Ln 29中,可以看到characters数组中有一些带有嵌套在data中的信息对象和一些没有嵌套的。所有这些都已被正确地标准化。

我还添加了一些部分来展示它如何处理数组和深度嵌套的数据,请参见publisher中的country模型。

由于缺乏id的存在,因此您将需要一个slug,每个模式也在示例中包含了id。

Normalizr非常棒,希望这有助于更好地解释它 :)


是的,我非常苦恼,因为我得到了所有嵌套字符、发布者等的未定义子键... 我对你的示例唯一做出的更改是我的实体中实际上有一个 { id } 键... 请参见:http://requirebin.com/?gist=db7d88f9866ff59aad62e01e6b6d630b - AndrewMcLagan
1
因为你的id属性是嵌套在data对象中的,所以你需要告诉normalizr具体检查那里才能找到它。看看这个:http://requirebin.com/?gist=26b016c32f130c8b23024ef045e9d221 :) - horyd
谢谢 :-) 尽管我的用例略有不同...数组项始终以 { data } 为键,例如 { characters: data: [...] }。非常感谢您的帮助。似乎无法解决这个问题。 - AndrewMcLagan
这真的有点失控了 :-) 它没有按预期工作。可能无法将数组分配给 output,normalizr 似乎忽略了这一点。我已经设计了 bin 示例:http://requirebin.com/?gist=76f79fb6cd4990a4c88131fb4b151958 当我们解决这个问题时,我会更新我的答案... - AndrewMcLagan
那也是我的想法...运行任意的前/后归一化函数。虽然最终我控制了我的API,现在它已经完全在服务器端进行了归一化处理。更好。对客户端来说更加经济,CPU也更好,你知道那个你不知道的。话虽如此,我会想出一个答案的。非常感谢您的努力,非常感激!! - AndrewMcLagan
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接