Creates a resource and associated actions and selectors to interact with it
-
(resourceName): (
string
) The name under which the resource will be stored in the state -
(options): (
object
) An object containing additional, optional options for the resource:A. (cacheLifetime): (
number
, default: 0) The duration (in seconds) for which the resource will be considered valid (from0
- no cache - toInfinity
- cached permanently)B. (denormalizer): (
(resourceIds, resources) : array<resources>
, default null) A function useful to denormalize nested objects which have been normalized byactionName.normalizer
(e.g. via normalizr) -
(actions): (
map<actionName:config>
) An object of configs with the following attributes:
const resource = {
[actionName]: {
// Mandatory
method: 'GET|POST|PATCH|PUT|DELETE',
url: string || func,
// Optional
beforeHook: func,
normalizer: func,
metadataNormalizer: func,
afterHook: func,
// Also optional. Override the built-in network helpers
// and the ones you may have provided using initializeNetworkHelpers
networkHelpers: {
getToken: func,
requestGET: func,
requestPATCH: func,
requestPUT: func,
requestPOST: func,
requestDELETE: func,
handleStatusCode: func,
handleError: func,
},
},
...
};
Extensive documentation on actions configuration can be found here.
(Object): An object containing actions and selectors.
const resource = {
actions: object,
selectors: object,
};
This example demonstrates how to use createResource
to create a sample resource, and then to export the reducers, actions and selectors.
import { createResource } from '@brigad/redux-rest-easy';
const users = createResource('users', { cacheLifetime: 30 })({
retrieve: {
method: 'GET',
url: 'https://my-api.com/users',
beforeHook: () => console.log('About to retrieve users... Hang on!'),
},
retrieveById: {
method: 'GET',
url: 'https://my-api.com/users/::userId',
},
create: {
method: 'POST',
url: 'https://my-api.com/users',
afterHook: () => console.log('User created!'),
normalizer: ({ user }) => ({
entities: { users: { [user.id]: user } },
result: user.id,
}),
},
edit: {
method: 'PATCH',
url: 'https://my-api.com/users/::userId',
},
});
const {
actions: {
resource: {
invalidate: invalidateUsers,
invalidateId: invalidateUser,
reset: resetUsers,
},
retrieve: { perform: retrieveUsers, invalidate: invalidateRetrieveUsers },
retrieveById: { perform: retrieveUser, invalidate: invalidateRetrieveUser },
create: { perform: createUser },
edit: { perform: editUser },
},
selectors: {
resource: { getResource: getAllUsers, getResourceById: getUserById },
retrieve: {
resource: {
couldPerform: couldRetrieveAnyUsers,
isPerforming: isRetrievingAnyUsers,
hasSucceeded: hasRetrievedAnyUsers,
hasFailed: hasFailedAnyUsers,
isValid: areAllUsersValid,
couldPerformOnId: couldRetrieveUser,
isPerformingOnId: isRetrievingUser,
hasSucceededOnId: hasRetrievedUser,
hasFailedOnId: hasFailedUser,
isValidId: isUserValid,
},
request: {
getResource: getUsers,
getMetadata: getUsersMetadata,
couldPerform: couldRetrieveUsers,
isPerforming: isRetrievingUsers,
hasSucceeded: hasRetrievedUsers,
hasFailed: hasFailedUsers,
isValid: areUsersValid,
},
},
},
} = users;
export {
retrieveUsers,
retrieveUser,
createUser,
editUser,
invalidateUsers,
invalidateUser,
invalidateRetrieveUsers,
invalidateRetrieveUser,
resetUsers,
getAllUsers,
getUserById,
couldRetrieveAnyUsers,
isRetrievingAnyUsers,
hasRetrievedAnyUsers,
hasFailedAnyUsers,
areAllUsersValid,
couldRetrieveUser,
isRetrievingUser,
hasRetrievedUser,
hasFailedUser,
isUserValid,
getUsers,
getUsersMetadata,
couldRetrieveUsers,
isRetrievingUsers,
hasRetrievedUsers,
hasFailedUsers,
areUsersValid,
};
- The above example is very exhaustive, but you can export only what you really need
- Naming is a matter of personal preference, use what works for you
- You can alternately just export
users
, and spare yourself the trouble of mapping the names. Then just use the selectors like so:users.selectors.resource.getResource()
. Again, use what works for you