• Stars
    star
    577
  • Rank 77,363 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created almost 8 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Normalize JSON API data for redux applications

json-api-normalizer

Utility to normalize JSON API data for redux applications

npm version Downloads Build Status Coverage Status

Description

json-api-normalizer helps awesome JSON API and redux work together. Unlike normalizr json-api-normalizer supports JSON API specification, which means that you don't have to care about schemes. It also converts collections into maps, which is a lot more suitable for redux.

Demo - https://yury-dymov.github.io/json-api-react-redux-example/

Demo sources - https://github.com/yury-dymov/json-api-react-redux-example

Works great together with redux-object, which helps to fetch and denormalize data from the store.

json-api-normalizer was recently featured in SmashingMagazine: https://www.smashingmagazine.com/2017/05/json-api-normalizer-redux/

Install

$ npm install json-api-normalizer

Example

import normalize from 'json-api-normalizer';

const json = {
  data: [{
    "type": "post-block",
    "relationships": {
      "question": {
        "data": {
          "type": "question",
          "id": "295"
        }
      }
    },
    "id": "2620",
    "attributes": {
      "text": "I am great!",
      "id": 2620
    }
  }],
  included: [{
    "type": "question",
    "id": "295",
    "attributes": {
      "text": "How are you?",
      id: 295
    }
  }]
};

console.log(normalize(json));
/* Output:
{
  question: {
    "295": {
      id: 295,
      type: "question"
      attributes: {
        text: "How are you?"
      }
    }
  },
  postBlock: {
    "2620": {
      id: 2620,
      type: "postBlock",
      attributes: {
        text: "I am great!"
      },
      relationships: {
        question: {
          type: "question",
          id: "295"
        }
      }
    }
  }
}
*/

Options

Endpoint And Metadata

While using redux, it is supposed that cache is incrementally updated during the application lifecycle. However, you might face an issue if two different requests are working with the same data objects, and after normalization, it is not clear how to distinguish, which data objects are related to which request. json-api-normalizer can handle such situations by saving the API response structure as metadata, so you can easily get only data corresponding to the certain request.

console.log(normalize(json, { endpoint: '/post-block/2620' }));
/* Output:
{
  question: {
    ...
  },
  postBlock: {
    ...
  },
  meta: {
    "/post-block/2620": {
      data: [{
        type: "postBlock",
        id: 2620,
        relationships: {
          "question": {
            type: "question",
            id: "295"
          }
      }]
    }
  }
}
*/

Endpoint And Query Options

By default request query options are ignored as it is supposed that data is incrementally updated. You can override this behavior by setting filterEndpoint option value to false.

const d1 = normalize(json, { endpoint: '/post-block/2620?page[cursor]=0' });
const d2 = normalize(json, { endpoint: '/post-block/2620?page[cursor]=20' });
console.log(Object.assign({}, d1, d2));
/* Output:
{
  question: {
    ...
  },
  postBlock: {
    ...
  },
  meta: {
    "/post-block/2620": {
      ...
    }
  }
}
*/

const d1 = normalize(json, { endpoint: '/post-block/2620?page[cursor]=0', filterEndpoint: false });
const d2 = normalize(json, { endpoint: '/post-block/2620?page[cursor]=20', filterEndpoint: false });
console.log(someFunctionWhichMergesStuff({}, d1, d2));
/* Output:
{
  question: {
    ...
  },
  postBlock: {
    ...
  },
  meta: {
    "/post-block/2620: {
      "?page[cursor]=0": {
        ...
      },
      "?page[cursor]=20": {
        ...
      }
    }
  }
}
*/

Pagination And Links

If JSON API returns links section and you define the endpoint, then links are also stored in metadata.

const json = {
  data: [{
    ...
  }],
  included: [{
    ...
  }],
  links: {
    first: "http://example.com/api/v1/post-block/2620?page[cursor]=0",
    next: "http://example.com/api/v1/post-block/2620?page[cursor]=20"
  }
};

console.log(normalize(json, { endpoint: '/post-block/2620?page[cursor]=0'}));
/* Output:
{
  question: {
    ...
  },
  postBlock: {
    ...
  },
  meta: {
    "/post-block/2620": {
      data: [{
        ...
      }],
      links: {
        first: "http://example.com/api/v1/post-block/2620?page[cursor]=0",
        next: "http://example.com/api/v1/post-block/2620?page[cursor]=20"
      }
    }
  }
}
*/

Lazy Loading

If you want to lazy load nested objects, json-api-normalizer will store links for that

const json = {
  data: [{
    attributes: {
      ...
    },
    id: "29",
    relationships: {
      "movie": {
        "links": {
          "self": "http://...",
          "related": "http://..."
        }
      },
    },
    type: "question"
  }]
};

console.log(normalize(json));
/* Output:
{
  question: {
    "29": {
      attributes: {
        ...
      },
      relationships: {
        movie: {
          links: {
            "self": "http://...",
            "related": "http://..."
          }
        }
      }
    }
  }
}
*/

Camelize Keys

By default all object keys and type names are camelized, however, you can disable this with camelizeKeys option.

const json = {
  data: [{
    type: "post-block",
    id: "1",
    attributes: {
      "camel-me": 1,
      id: 1
    }
  }]
}

console.log(normalize(json));
/* Output:
{
  postBlock: {
    "1": {
      id: 1,
      type: "postBlock",
      attributes: {
        camelMe: 1
      }
    }
  }
}
*/

console.log(normalize(json, { camelizeKeys: false }));
/* Output:
{
  "post-block": {
    "1": {
      id: 1,
      type: "postBlock",
      attributes: {
        "camel-me": 1
      }
    }
  }
}
*/

Camelize Type Values

By default propagated type values are camelized but original value may be also preserved

const json = {
  data: [{
    type: "post-block",
    id: "1",
    attributes: {
      "camel-me": 1,
      id: 1
    }
  }]
}

console.log(normalize(json, { camelizeTypeValues: false }));
/* Output:
{
  postBlock: {
    "1": {
      id: 1,
      type: "post-block", // <-- this
      attributes: {
        camelMe: 1
      }
    }
  }
}
*/

Copyright

MIT (c) Yury Dymov

More Repositories

1

react-autocomplete-input

Autocomplete input field for React
JavaScript
197
star
2

redux-object

Builds complex JS object from normalized redux store. Best works with json-api-normalizer
JavaScript
138
star
3

habr-app

React tutorial for Habrahabr
JavaScript
114
star
4

redux-oauth

Bearer token-based authentication library with OAuth2 support for redux applications.
JavaScript
67
star
5

smashing-react-i18n

Internationalizing React App Boilerplate For SmashingMagazine
JavaScript
62
star
6

react-bootstrap-timezone-picker

Timezone picker for react-bootstrap
JavaScript
30
star
7

react-bootstrap-button-loader

React ButtonLoader with Bootstrap flavor
JavaScript
26
star
8

json-api-react-redux-example

React Application With Redux And JSON API
JavaScript
25
star
9

realistic-ui-concept

Realistic UI — the Optimistic UI alternative
JavaScript
19
star
10

react-bootstrap-time-picker

Bootstrap Time Picker React Component
JavaScript
17
star
11

js-regex-pl

Providing \p{L} regex pattern for JavaScript RegExp
JavaScript
12
star
12

redux-oauth-client-demo

Redux OAuth demo for client-side.
JavaScript
12
star
13

redux-oauth-demo

Redux OAuth universal / isomorphic application demo
JavaScript
9
star
14

smashing-app

React App for Smashing Magazine
JavaScript
5
star
15

get-input-selection

JavaScript
4
star
16

phoenix-json-api-example

JSON API web service example
JavaScript
4
star
17

redux-oauth-backend-demo

Simple rails-api backend application for redux-oauth library demo
Ruby
3
star
18

intl-polyfill

Shallow Intl Polyfill for react-intl
JavaScript
2
star
19

disrupt

Swift
1
star
20

kzbank

Demo Backend for National Bank of Kazakhstan
Ruby
1
star
21

InfPagedScrollView

ios infinite scrolling with paging. Influenced by UITableView
Objective-C
1
star