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?
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)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With