如何使用“normalizr”规范化这个简单的 API 响应?

Posted

技术标签:

【中文标题】如何使用“normalizr”规范化这个简单的 API 响应?【英文标题】:How to normalize this simple API response using "normalizr"? 【发布时间】:2020-04-24 08:41:17 【问题描述】:

我有这个来自 API 的响应...


    "current_page": 1,
    "data": [
        
            "id": 1,
            "category_id": 1,
            "creator_id": 1,
            "instructor_id": 1,
            "difficulty_id": 1,
            "status_id": 1,
            "title": "hebae",
            "overview": "Course Overview",
            "deleted_at": null,
            "created_at": "2020-01-02 15:16:08",
            "updated_at": "2020-01-02 15:16:08"
        ,
        
            "id": 2,
            "category_id": 1,
            "creator_id": 1,
            "instructor_id": 2,
            "difficulty_id": 1,
            "status_id": 1,
            "title": "update course 1",
            "overview": "Course Overview",
            "deleted_at": null,
            "created_at": "2020-01-02 15:18:40",
            "updated_at": "2020-01-02 15:19:06"
        ,
        
            "id": 3,
            "category_id": 1,
            "creator_id": 1,
            "instructor_id": 1,
            "difficulty_id": 1,
            "status_id": 1,
            "title": "hebaTest",
            "overview": "Course Overview",
            "deleted_at": null,
            "created_at": "2020-01-02 15:24:09",
            "updated_at": "2020-01-02 15:24:09"
        ,
        
            "id": 4,
            "category_id": 2,
            "creator_id": 1,
            "instructor_id": 1,
            "difficulty_id": 1,
            "status_id": 1,
            "title": "hebaTest",
            "overview": "Adile",
            "deleted_at": null,
            "created_at": "2020-01-02 15:25:03",
            "updated_at": "2020-01-02 15:25:03"
        ,
        
            "id": 5,
            "category_id": 2,
            "creator_id": 1,
            "instructor_id": 1,
            "difficulty_id": 1,
            "status_id": 1,
            "title": "hebaTest",
            "overview": "Adile",
            "deleted_at": null,
            "created_at": "2020-01-02 15:33:06",
            "updated_at": "2020-01-02 15:33:06"
        ,
        
            "id": 6,
            "category_id": 1,
            "creator_id": 1,
            "instructor_id": 1,
            "difficulty_id": 1,
            "status_id": 1,
            "title": "Course Title",
            "overview": "Course Overview",
            "deleted_at": null,
            "created_at": "2020-01-05 08:24:56",
            "updated_at": "2020-01-05 08:24:56"
        ,
    ],
    "first_page_url": "http://skillboardbackend-staging.zph2jwe3pc.eu-west-1.elasticbeanstalk.com/api/course?page=1",
    "from": 1,
    "last_page": 2,
    "last_page_url": "http://skillboardbackend-staging.zph2jwe3pc.eu-west-1.elasticbeanstalk.com/api/course?page=2",
    "next_page_url": "http://skillboardbackend-staging.zph2jwe3pc.eu-west-1.elasticbeanstalk.com/api/course?page=2",
    "path": "http://skillboardbackend-staging.zph2jwe3pc.eu-west-1.elasticbeanstalk.com/api/course",
    "per_page": 15,
    "prev_page_url": null,
    "to": 15,
    "total": 29

我正在尝试将“数据”数组定义为“类别”对象,其余数据可以保持不变,如何使用 normalizr 做到这一点?

我试过这个...

const  data  = await apiGetAllCategories();

const dataSchema = new schema.Entity("categories");
const coursesSchema = new schema.Entity("info", 
    data: [dataSchema]
);
const normalizedData = normalize(data, coursesSchema);
console.log(normalizedData);

但它总是给我未定义的“信息”,而未定义的“结果”...

我在这里做错了什么?

【问题讨论】:

以上 API 响应似乎没有那么深的嵌套,它需要额外的库来提取任何数据。向我们展示所需的输出数据样本,我很确定有一个简单的 vanilla js 解决方案可供建议。 @YevgenGorbunkov 我只需要与响应相同的结构,除了数据是对象而不是数组,并且该对象的键是 id,就像我从“ normalizr”在屏幕截图的“类别”中。 【参考方案1】:

您的数据似乎已经是某种简化/规范化的形式,因为我没有看到任何嵌套或重复的数据结构。我认为对您的数据使用简单的 array::reduce 就足以满足您的需求。

// Reduce data array to map [element.id => element]
const dataObject = data.reduce((dataObject, item) => 
  dataObject[item.id] = item;
  return dataObject;
, );

const data = [
  
    id: 1,
    category_id: 1,
    creator_id: 1,
    instructor_id: 1,
    difficulty_id: 1,
    status_id: 1,
    title: "hebae",
    overview: "Course Overview",
    deleted_at: null,
    created_at: "2020-01-02 15:16:08",
    updated_at: "2020-01-02 15:16:08"
  ,
  
    id: 2,
    category_id: 1,
    creator_id: 1,
    instructor_id: 2,
    difficulty_id: 1,
    status_id: 1,
    title: "update course 1",
    overview: "Course Overview",
    deleted_at: null,
    created_at: "2020-01-02 15:18:40",
    updated_at: "2020-01-02 15:19:06"
  ,
  
    id: 3,
    category_id: 1,
    creator_id: 1,
    instructor_id: 1,
    difficulty_id: 1,
    status_id: 1,
    title: "hebaTest",
    overview: "Course Overview",
    deleted_at: null,
    created_at: "2020-01-02 15:24:09",
    updated_at: "2020-01-02 15:24:09"
  ,
  
    id: 4,
    category_id: 2,
    creator_id: 1,
    instructor_id: 1,
    difficulty_id: 1,
    status_id: 1,
    title: "hebaTest",
    overview: "Adile",
    deleted_at: null,
    created_at: "2020-01-02 15:25:03",
    updated_at: "2020-01-02 15:25:03"
  ,
  
    id: 5,
    category_id: 2,
    creator_id: 1,
    instructor_id: 1,
    difficulty_id: 1,
    status_id: 1,
    title: "hebaTest",
    overview: "Adile",
    deleted_at: null,
    created_at: "2020-01-02 15:33:06",
    updated_at: "2020-01-02 15:33:06"
  ,
  
    id: 6,
    category_id: 1,
    creator_id: 1,
    instructor_id: 1,
    difficulty_id: 1,
    status_id: 1,
    title: "Course Title",
    overview: "Course Overview",
    deleted_at: null,
    created_at: "2020-01-05 08:24:56",
    updated_at: "2020-01-05 08:24:56"
  
];

// Reduce data array to map [element.id => element]
const dataObject = data.reduce((dataObject, item) => 
  dataObject[item.id] = item;
  return dataObject;
, );

console.log(dataObject);

【讨论】:

我知道,你是绝对正确的,但我的想法是弄清楚模式和“normalizr”的一般工作方式以及为什么我得到“未定义”。我能够弄清楚我哪里出错了,那就是“normalizr”在顶层需要某种“id”,如果它找不到你就必须提供它,这就是我所做的... ` const dataSchema = new schema.Entity("data"); const courseSchema = new schema.Entity("info", data: [dataSchema] , idAttribute: "per_page" ); const normalizedData = normalize(数据,课程架构); ` 我会接受你的回答,因为这对我来说似乎是合乎逻辑的,但正如我所说,我试图找出我做错了什么。非常感谢:) @Ruby 您可以回答自己的问题,我认为您应该这样做,因为从技术上讲,这将是对原始问题的 正确 答案,而不仅仅是替代解决方案“有效”。【参考方案2】:

对于任何对如何使用“normalizr”标准化此响应感兴趣的人,我发现了我哪里出错了,normalizr 通常会在顶层寻找一个“id”键,如果它不能发现你必须提供它,在我的情况下,***对象上没有“id”,所以我给它“per_page”作为 id 让它工作......

const dataSchema = new schema.Entity("data");
const coursesSchema = new schema.Entity( "info", 
 
    data: [dataSchema]
,  idAttribute: "per_page"  );

const normalizedData = normalize(data, coursesSchema);

顺便说一句,@Drew Reese 提供的“答案”在我得到的这种平面对象响应中更简单、更清晰。

干杯:)

【讨论】:

以上是关于如何使用“normalizr”规范化这个简单的 API 响应?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Normalizr 定义递归模型的模式

如何在 Jbuilder 和 Normalizr 之间展平数据

Normalizr:规范化深层嵌套项

Normalizr 规范化嵌套数据

redux 中 normalizr 后的非规范化实体

为啥我有这个 Uncaught TypeError: (0 , _normalizr.arrayOf) is not a function?