# createResource

Creates a resource and associated actions and selectors to interact with it

## Arguments

1. (*resourceName*): (`string`) The name under which the resource will be stored in the state
2. (*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 (from `0` - no cache - to `Infinity` - cached permanently)

   B. (*denormalizer*): (`(resourceIds, resources) : array<resources>`, **default null**) A function useful to denormalize nested objects which have been normalized by `actionName.normalizer` (e.g. via [normalizr](https://github.com/paularmstrong/normalizr/blob/master/docs/api.md#denormalizeinput-schema-entities))
3. (*actions*): (`map<actionName:config>`) An object of configs with the following attributes:

```javascript
const resource = {
    // 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](https://brigad.gitbook.io/redux-rest-easy/docs/api/createresource/actionsconfig).

## Returns

(*Object*): An object containing [actions](https://brigad.gitbook.io/redux-rest-easy/docs/api/createresource/actions) and [selectors](https://brigad.gitbook.io/redux-rest-easy/docs/api/createresource/selectors).

```javascript
const resource = {
  actions: object,
  selectors: object,
};
```

## Example

This example demonstrates how to use `createResource` to create a sample resource, and then to export the reducers, actions and selectors.

```javascript
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,
};
```

## Tips

* 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
