ba-react-fetch-api
v0.12.60
Published
Data fetching API
Downloads
28
Readme
Fetch data from BluAvenu API
This package is aimed to provide cross platform (web/native) methods for fetching data from BluAvenu API server. It also adds some layer of abstraction allowing developers to call APIs using aliases instead of directly specifying API url paths. It is based on redux-api.
Index
Installation
npm install ba-react-fetch-api --save
Setup
Because of specificity of redux-api lib there are several steps required before using FetchAPI in real code:
- desrcibe data sources
- setup reducers
- define some helper functions.
Suggest you do all these operations in a single file e.g. rest/index.js
.
Data Sources
In order to setup reducers which are utilized for storing fetched data in redux store you need to describe sources of data. These are not reducers, but an array of objects which will be used for FetchAPI reducer init.
Example:
export const sources = [
{entity: 'campaigns', key: 'campaigns'},
{entity: 'cases', key: 'cases'},
{entity: 'contacts', key: 'contacts'},
{entity: 'relatedContacts', key: 'relatedContacts'},
{
entity: 'contact',
key : 'contact',
reducers: [detailsReducer({
modelStorePath: 'fetchApi.contact.data',
moduleName : 'contact',
})],
},
];
Data source options are:
entity
— names of entities is a limited set which is predefined in FetchAPI.key
— user defined name. Will be used for as redux store key name. E.g. you can usecontacts
for main list of Contacts andrelated_contacts
for lists of Contacts related to currently active app page.reducers
— array of extra reducers applied to fetched data.
Reducers
In your root reducer function put this:
import {sources as dataSources} from './rest';
import {reducers as fetchApiReducers} from 'ba-react-fetch-api';
combineReducers(
...,
fetchApi: fetchApiReducers(dataSources),
...,
)
Helpers
redux-api adds some compexity issues. In order to avoid them and make using FetchAPI easier helper methods introduced and suggested to be used along with FetchAPI. Setup them in rest/index.js
as mentioned below a long with data sources code from previous section:
import _ from 'lodash';
import {hoc as fetchApiHoc} from 'ba-react-fetch-api';
import {restByKey} from 'ba-react-fetch-api';
import settings from 'settings';
const
defaultParams = params => ({...params, baseURL: settings.API_PROXY_URL});
export const sources = [
{entity: 'campaigns', key: 'campaigns'},
{entity: 'cases', key: 'cases'},
{entity: 'contacts', key: 'contacts'},
{entity: 'relatedContacts', key: 'relatedContacts'},
{
entity: 'contact',
key : 'propertyOwner',
reducers: [detailsReducer({
modelStorePath: 'fetchApi.contact.data',
moduleName : 'contact',
})],
},
];
// Here come helpers
export const fetchApiList = params => fetchApiHoc.list(defaultParams(params)),
export const fetchApiDetails = params => fetchApiHoc.details(defaultParams(params)),
export const rest = params => restByKey({
baseURL: settings.baseURL,
key : _.isObject(params) ? params.key : params,
entity : params.entity,
sources
});
restByKey()
Initializes redux-api rest object, which provides methods for doing http requests.
Using rest()
from the code above following example will do a GET-request and put returned data into fetchApi.contacts
key of redux store (considering reducers were defined like in an example above):
rest({entity: 'contatcs', key: 'related_contacts'}).sync();
// Considering you have a defined source object, with key="contacts"
rest({key: 'contatcs'}).sync()
// Pass just string, which will find a source with key equal passed string, or create one with
// entity and key equal passed string
rest('contatcs').sync()
Usage
Higher Order Component
Its goal is to provied wrapped component with data fetched and stored in redux store. And also to provide methods for fetching data or performing CRUD requests.
Porperties and methods which came to wrapped component from FetchAPI hocs are stored in props.faFetched.<key param>
.
Apply it like this:
import _ from 'lodash';
import {fetchApiList} from 'rest';
const
ContactsList = props => <div>
{_.map(props.faFetched.contacts.data, contact => <div>{contact.personal.first_name}</div>)}
</div>;
compose(
fetchApiList({
entity: 'contacts',
// These are GET-request params
queryParams: props => {search: props.searchValue},
filters: 'filter.savedFilters',
key : 'contacts',
page : `incrementalList.someUniqueId.page`,
sorting: `table.someUniqueId.sorting`,
}),
)(ContactsList);
List HOC
import {hoc} from 'ba-react-fetch-api';
compose(
hoc.list(...),
)();
Params
entity: string
— due to some design decisions you have to duplicate entity name when applying a hockey: string
— the one defined in data sources arrayfilters?: string | Array
— filtering params values or path in redux storefetchOnMount?: boolean
— if passedtrue
data will be fetched during component mount, otherwise fetch will only happen when hoc params changespage?: string | number
— current page value or its path in redux storesorting?: Object
— sorting params values or path in redux storestatePath?: string
— path to redux store of FetchAPI reducer, default isfetchApi
queryParams?: (props: Object) => Object
— extra params applied to GET query string or POST/PUT body, passed with component props when calledurlParams?: (props: Object) => Object
— url pattern params, like{id: '1a'}
to be applied as:id
in such url pattern/contacts/:id
, passed with component props when called.
For data structure expected for filters
, page
and sorting
refer to types annotations — https://github.com/chunkytae/ba-react-fetch-api/blob/master/FetchAPI/hoc/list.js
Methods
data
— fetched data arrayreset()
— reset data in redux storesync(urlParams: Object, params: Object)
— fetch data.
Filtering
As mentioned above in order to apply filtering to list hoc pass string representing redux store path or array of objects in filters
param.
Filter item types definitions can be found here.
Important Currently filter item data structure includes two similar properties value
and compiledValue
. Always use value
. compiledValue
is deprecated.
Value format
value
must be passed as string
and can take either string/numeric or range or set of options:
- range
- date
[2005-08-09T15:31:42+03:30,2005-08-09T18:20:42+03:30]
- numeric
[55,170]
- date
- set —
[585be5845d0000d1057c4174, 592b2c814f0000993428eb47, 592b105b4f0000243328e9fc]
.
In case of date value format it accepts set of special options:
- yesterday
- today
- tomorrow
- next_week
- last_week
- next_month
- last_month.
Possible operator options
Set of operator
options depend on filter value
type. It means that operators will differ for string and date values:
- numeric — eq, not-eq, lt, lt-eq, gt, gt-eq, empty, non-empty
- string — is, is-not, contains, not-contain, starts-with, ends-with, empty, non-empty
- dates — eq, not-eq, lt, lt-eq, gt, gt-eq, empty, non-empty
- lookup — value which accepts predefined set of ids, like in
value
example above. Options are — in, not-in, empty, non-empty.
Sorting
Only sorting by single field is available. Takes the string representing redux store path or following object:
// {column: string, order: asc | desc}
{column: 'meta._created', order: 'desc'}
Details HOC
import {hoc} from 'ba-react-fetch-api';
compose(
hoc.details(...),
)(Component);
Params
entity: string
— due to some design decisions you have to duplicate entity name when applying a hockey: string
— the one defined in data sources arrayfetchOnMount?: boolean
— if passedtrue
data will be fetched during component mount, otherwise fetch will only happen when hoc params changesstatePath?: string
— path to redux store of FetchAPI reducer, default isfetchApi
queryParams?: (props: Object) => Object
— extra params applied to GET query string or POST/PUT body, passed with component props when calledurlParams?: (props: Object) => Object
— url pattern params, like{id: '1a'}
to be applied as:id
in such url pattern/contacts/:id
, passed with component props when called.
Methods
data
— fetched data objectdelete(urlParams: Object)
— send DELETE requestetag
— this token is required for every PUT request, meaning for every single data update requestpost(urlParams: Object, params: {body: string, headers: Object})
— send POST request. Useparams
for sending requestbody
and headers.body
must a valid stringified json.put(urlParams: Object, params: {body: string, headers: Object})
— same as POST.reset()
— reset data in redux storesync(urlParams: Object, params: Object)
— fetch data.
Calling redux-api actions directly
In some cases you need to perform single API request but do not require any fetched data to be applied to component. For such situations you can dispatch redux-api actions directly, without applying hoc to your component.
Import helper function from rest/
and use it like this:
import _ from 'lodash';
import {fetchApiList, rest} from 'rest';
const
ContactsList = props => <div>
{_.map(props.faFetched.contacts.data, contact => <div>
{contact.personal.first_name}
<button onClick={() => props.deleteContact(contact._id)}>Delete</button>
</div>)}
</div>;
compose(
fetchApiList({
entity: 'contacts',
// These are GET-request params
fetchParams: props => {search: props.searchValue},
filters: 'filter.savedFilters',
key : 'contacts',
page : `incrementalList.someUniqueId.page`,
sorting: `table.someUniqueId.sorting`,
}),
withHandlers({
deleteContact: props => id => rest('contact').delete({id: id}, error => {
if(!error)
console.log('Item removed!');
}),
}),
)(ContactsList);
Batch request
Batch API allows client to put several API calls into a single HTTP request having multiple responses returned in single one.
In order to use batch requests:
Update your data sources
export const sources = [
{entity: 'batch', key: 'opportunitiesStages'},
];
Call it in a component
import {restByKey} from 'ba-react-fetch-api';
import {sources} from 'your/data/sources/file';
restByKey({
key: 'opportunitiesStages',
sources: sources
}).post(
null,
{body: JSON.stringify([
{
url: 'http://104.236.30.5:9999/crm/v1/contacts',
key: 'contacts',
},
{
url: 'http://104.236.30.5:9999/crm/v1/accounts',
key: 'accounts',
}
])}
);
Now in redux store you have multiple responses in the format of:
[
{
"contacts": {}
},
{
"accounts": {}
}
]
Usage via hoc
import {connect} from 'react-redux';
import {hoc as fetchApiHoc} from 'ba-react-fetch-api';
compose(
fetchApiHoc.batch({
entity : 'batch',
fetchOnMount: true,
key : 'myBatch',
requests: () => ([
{
url: 'http://45.55.45.137:9999/crm/v1/contacts',
key: 'contacts',
},
{
url: 'http://45.55.45.137:9999/crm/v1/accounts',
key: 'accounts',
}
])
}),
connect(state => ({
requests: state.fetchApi.myBatch,
})),
)(SomeComponent);