Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Normalizing JSON API Standard v1

Tags:

json

flux

redux

api

I've been looking into normalizr for flattening JSON API data formatted in the standard JSON API format. Can anyone point me to some examples of this being done? I am specifically getting hung up on how to handle the normalizr schema for the relationships of a resource object (as defined by the JSON API standard). In the JSON API standard, there is a "relationships" property defined within the resource object and then properties for each group of related objects. Here's an example of a single product category in the JSON API format with two related products:

{
  "jsonapi": {
    "version": "1.0"
  },
  "meta": {
    "time": "0.006"
  },
  "data": [
    {
      "type": "category",
      "id": "6",
      "attributes": {
        "name": "Odwalla"
      },
      "meta": {
        "product_count": "0"
      },
      "relationships": {
        "product": {
          "data": [
            {
              "type": "product",
              "id": "4785"
            },
            {
              "type": "product",
              "id": "4786"
            }
          ]
        }
      }
    }
  ],
  "included": [
    {
      "type": "product",
      "id": "4786",
      "attributes": {
        "name": "Strawberry & Banana Odwalla",
        "description": null,
        "price": "3.19",
        "upc": ""
      }
    },
    {
      "type": "product",
      "id": "4785",
      "attributes": {
        "name": "Blueberry Odwalla",
        "description": null,
        "price": "3.19",
        "upc": ""
      }
    }
  ]
}

The products contained within the category are listed under data.relationships.product.data and those product objects are included in the included array. I am sure there are a number of ways to normalize this; what would be the most effective and friendly way to flatten this for a Flux/Redux store?

like image 882
aStewartDesign Avatar asked Feb 08 '23 15:02

aStewartDesign


1 Answers

As far as I understand json:api provides normalized data. Related data is not nested directly with the primary resource but included — see this Compound Documents and Fetching Includes. normalizr isn’t meant for this kind of data structure but you can easily build something that will you give you the same result as normalizr if this is your intention. Due to the fact that json:api is a very strict standard its quite great to work with. Thats is how I would try to achieve this, with a lot of ‘inspiration’ from the normalizr library …

import { reduce, append } from 'ramda'

export default function normalize({data, included}) {
  let bag = {}
  const result = visit(data, bag)
  visit(included, bag)

  return {
    entities: bag,
    result
  }
}

function visitIterable(obj, bag) {
  return reduce((acc, item) => {
    const entityId = visitEntity(item, bag)
    return append(entityId, acc)
  }, [], obj)
}

function visitEntity(obj, bag) {
  const entityKey = obj.type
  const entityId = obj.id

  if (!bag.hasOwnProperty(entityKey)) {
    bag[entityKey] = {}
  }

  bag[entityKey][entityId] = obj
  return entityId
}

function visit(obj, bag) {
  if (Array.isArray(obj)) {
    return {
      list: visitIterable(obj, bag)
    }
  } else if (typeof obj === 'object') {
    return {
      item: visitEntity(obj, bag)
    }
  }
}
like image 116
Ferdinand Salis-Samaden Avatar answered Feb 12 '23 10:02

Ferdinand Salis-Samaden