redux-jsonapi
v1.1.3
Published
Redux reducer, actions, and serializers for JSON:API
Downloads
93
Readme
Redux JSON:API
Redux JSON:API is a collection of actions and reducers for Redux that help ease the use of a JSON:API compliant API.
JSON:API is amazing for data transport, but once a client has the data it can be a little frustrating to work with. Redux JSON:API takes the guess-work and bike-shedding about how to structure, store, and use your JSON:API data in a Redux application.
Instalation
To install the stable version:
npm install --save redux-jsonapi
Usage
The Basics
The following will fetch a widget from GET http://example.com/widgets/1
(including it's associated foobars) add it to the application state under api
(indexed by it's ID), and output the new state to the console.
import { createStore, combineReducers } from 'redux';
import { apiReducer, apiActions, createApiMiddleware } from 'redux-jsonapi';
const reducers = combineReducers({
api: apiReducer
})
const apiMiddleware = createApiMiddleware('http://example.com');
const store = createStore(reducers, applyMiddleware(apiMiddleware);
store.subscribe(() => {
console.log(store.getState().api);
});
store.dispatch(apiActions.read({ id: 1, _type: 'widgets' }, {
params: {
include: 'foobars'
},
}));
Creating a widget via the API and adding it to the application state on success isn't much more complicated:
store.dispatch(apiActions.write({ _type: 'widgets', name: 'Super Cool Widget' }));
Updating an existing record is nearly identical - simply make sure the resource has an ID property:
store.dispatch(apiActions.write({ _type: 'widgets', id: 1, name: 'Super Cool Widget With A New Name' }));
Deleting a record is very similar:
store.dispatch(apiActions.remove({ _type: 'widgets', id: 1 }));
Nested Resources
To access the entities on a nested URL, provide an array of parent resources to the action. The following will fetch the entities from GET http://example.com/widgets/1/doodads
:
store.dispatch(apiActions.read([{ _type: 'widgets', id: 1 }, { _type: 'doodads' }]));
Note: the order of resources in the array determines the order of nesting.
Custom Headers
You can extend the default headers by simply passing an object as 2nd parameter into createApiMiddleware
.
const apiMiddleware = createApiMiddleware('http://example.com', {
Authorization: 'JWT Token'
});
With each apiActions
method you can provide additional headers as well
store.dispatch(apiActions.read({ id: 1, _type: 'widgets' }, {
params: {
include: 'foobars'
},
headers: {
cookies: 'MyCookie'
}
}));
Using Data
Data received from the JSON:API store is normalized into categories by resource type, and indexed by the resource's ID. The structure looks something like the following:
{
api: {
widgets: {
1: {
id: 1,
type: 'widgets',
attributes: {
name: 'Super Cool Widget',
},
relationships: {
doodad: {
data: {
id: 1,
type: 'doodads',
}
}
}
},
2: { ... },
},
doodads: {
1: {
id: 1,
type: 'doodads',
attributes: {
name: 'Nifty Doodad',
},
},
2: { ... },
}
}
}
Since often the data that we receive from the API contains associations to other resources, this isn't a very easy structure to work with out of the box. Redux JSON:API contains utilities that make serializing and deserializing resources between the JSON:API structure and a vanilla Javascript object structure much easier.
The following will fetch a widget from the API at /widgets/1, and upon being loaded into the Redux state it will log a deserialized instance of it to the console.
import { apiActions, deserialize } from 'redux-jsonapi';
store.subscribe(() => {
const { api } = store.getState();
const widget = deserialize(api.widgets[1], api);
console.log(widget);
});
store.dispatch(apiActions.read({ id: 1, _type: 'widgets' }));
The denormalized instance looks something like this:
const widget = {
_type: 'widgets',
id: 1,
name: 'Super Cool Widget',
doodad: function() { // Calling this returns the associated doodad }
}
With this new denormalized resource, we can access the widget's name via widget.name
, and it's associated doodad by calling widget.doodad()
.
When it comes time to update the widget, simply change it's values and dispatch the apiActions.write
action with the object.
widget.name = 'New Name';
widget.doodad = () => newDoodad;
store.dispatch(apiActions.write(widget));
Example
See the example directory.
License
MIT