Redux Chunk
📤 A redux library to declaratively interact with any API
Redux Chunk allows you to define your API endpoints across chunks in webpack chunked application. For large APIs, it makes sense to dynamically add paths to your SDK-style endpoints list and it improves the separation of concerns, with each action file defining it's own endpoints and request structure.
There are many API helpers for Redux, we based this library off redux-bees but we created (read: copied) this library to work with APIs that may not be standardized. i.e. it doesn't use JSON API 100%. If your API does, you should consider using redux-bees
.
Install
npm install redux-chunk --save
Usage
You can use Redux Chunk in your existing Redux app by following these steps:
Add the redux-chunk reducer and middleware to your Redux store
; ; const reducer = ; const store = ;
Create an API helper file
You can define general endpoints in your main bundle or wait to define endpoints in chunked actions. You can configure dynamic headers such as adding the user's access token to Authorization
when they are logged in.
;; // The result of your createStore const endpoints = getItems: method: get path: '/items' getItem: method: get path: '/items/:id' createItem: method: post path: '/items' updateItem: method: patch path: '/items/:id' deleteItem: method: destroy path: '/items/:id' ;const options = baseUrl: 'https://api.example.com' ...headers Authorization: `Bearer ` ; const api = endpoints options; ;
Dynamic Base URL
const options = path > -1 ? 'https:://other.example.com' : 'https://api.example.com';
Resolve/Reject middleware
If you need to execute specific code before or after every request or retry a request if a particular response is returned, you can use the handleResolve
and handleReject
options:
const options = baseUrl: 'https://api.example.com' { // Only return the result, the request is given to you here for checking sent placeholders or headers return Promise; } { ifresbodymessage > -1 // Refresh the access token then retry the request using .retry() method return req; return Promise; };
You can then perform API actions like this:
api ;
The arguments you pass to your endpoint depend on the HTTP method and the presence of placeholders in the path declared for the endpoint.
api;// GET https://api.example.com/items/12 api;// GET https://api.example.com/items/12?custom=query api;// POST https://api.example.com/items api;// PATCH https://api.example/items/12 api;// DELETE https://api.example.com/items/12
If you perform multiple concurrent requests to the same endpoint with the same parameters, a single API call will be performed, and every request will be attached to the same promise:
api ; // This won't produce a new API call api ;
Use it in your Redux actions
You can dispatch the API request promises as Redux actions which are stored in the state of your application under an api
key.
const getItem = { return api;};
With redux-thunk
:
const getItem = { return { // Asynchronous things here };};
It's also possible to mutate the result:
const getItem = { const placeholders = id ; const req = api; req; // Requires these to be added back to the Promise sequence reqactionName = 'getItem'; reqparams = options: {} placeholders ; return req;};
Accessing the results in Redux state
The results of your API requests are cached in the api
section of your Redux state. It should be considered private, and accessed via the query
state selector.
store;// {// api: {// getItem: {// '{}': {// isLoading: false,// error: null,// headers: {...},// status: 200,// result: [...]// },// '{"id":12}': {// isLoading: false,// error: null,// headers: {...},// status: 200,// result: {...}// }// }// }// }
The query
function takes the following arguments:
- query(state, apiCall)
- query(state, apiCall, placeholders)
If you don't include placeholders, the query will return all requests that have been made to that endpoint.
Examples:
// {// hasStarted: true,// isLoading: false,// hasFailed: false,// result: { id: 12, name: 'my-item', price: 100 }// headers: {...},// status: 200,// error: null,// } // {// hasStarted: true,// isLoading: false,// hasFailed: false,// result: [// { payload: { id: 12, name: 'my-item', price: 100 }, params: { id: 12 } }// ],// headers: [...],// status: 200,// error: null// }
Accessing the results in your React Components
To make it easier to integrate data fetching in React Components, you can use the query
state selector inside a connect
HOC from the react-redux
lib.
;;; ; const App = <div className="app"> itemresult && !itemisLoading ? <p>itemname</p> : itemhasFailed ? <p>itemerror</p> : <p>Loading...</p> </div>; item: App;
Adding more endpoints
In action files that are loaded in by chunked modules, you can add new endpoints to your built API with the addEndpoints
function.
; ; api; const getPosts = { return api;};