Search code examples
javascriptreactjsreduxnormalizrreselect

Redux normalizr - nested API responses


How can I use normalizr to deal with nested standardised JSON API responses that are key via the { data: ... } standard?

For example a 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,
            }
        }
    }
}   

How would I design schemas to deal with the nested data key?


Solution

  • I believe what you're after is the use of the assignEntity function which can be passed in the options of normalize. In this instance it lets us, where appropriate, filter out the redundant data properties and go straight to the values underneath.

    Effectively assignEntity let's you control how each key of data is normalized. Take a look here for a little more on how it works.

    I put this together as a demonstration, take a look: http://requirebin.com/?gist=b7d89679202a202d72c7eee24f5408b6. Here's a snippet:

    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;
      }
    }});
    

    Also see in particular Ln 29, where the array of characters has some objects with the information nested within data and some without. All are normalized correctly.

    I also added some parts to show how it works with arrays and deeply nested data, see the country model within publisher.

    With the data provided you will need a slug due to the absence of id's, which each schema also contains in the example.

    Normalizr is fantastic, I hope that helps explain a little more about it :)