I'm working on a project where we ended up writing our own dataProvider since our api is not strictly restful.
It's a bit of a pita to wrap your head around but once you figure out the workflow it's not too bad.
Basically there are three things that happen when dataProvider is called
- dataProvider uses the params to call convertDataProviderRequestToHTTP which returns a url and options that are used for sending a fetch/api call (building the request)
- fetch request/api call is sent (sending the request)
- dataProvider returns the results of calling convertHTTPResponseToDataProvider which converts the response into something that's useful to the Resource that's receiving it (handling the response from the request)
Here's a link to the relevant part of the react-admin documentation
https://marmelab.com/react-admin/DataProviders.html#writing-your-own-data-provider
Our solution uses switch statements whose cases are types and then each case has logic to handle different resources.
I'm not sure if this is the intended implementation but we ended up with something like this:
// import all the things
// set your api path prefix
const convertDataProviderRequestToHTTP = (type, resource, params) => {
//switch statement with one case for each action type
// and some logic where necessary for different resources ie.
switch(type){
case "GET_ONE":{
// if statements to handle resources with goofy endpoints
if(resource === 'abc/def'){
const url = `${API_PREFIX}/abc/def`;
const options = {
// set the specific options that you need for a
// each particular resource
}
}
// handles resources with normal restful endpoints
const url = `${API_PREFIX}/${RESOURCE}`;
const options = {
// this part depends on how you're doing your fetching
// might need to include the particular rest verb
// and any other settings
}
}
}
return {
url,
options
}
}
const convertHTTPResponseToDataProvider = (response, type, resource, params){
// another switch statement that converts the response that you get
// from your api to something that's useful to your Resource
switch(type){
case 'GET_ONE':{
if(resource === 'abc/def'){
// convert response into something useful and return it
return{
data: convertedResponse
}
}
}
}
}
export default (type, resource, params) => {
// this comes from react-admin, you could use plain old fetch or
// your favorite fetch library like axios instead
const { fetchJson } = fetchUtils;
// part 1, using the stuff that was sent in the dataProvider
// call to generate what you need to sending your fetch
const { url, options } = convertDataProviderRequestToHTTP(
type,
resource,
params
);
// add logic for grabbing your tokens and adding headers to options here
options.headers.set('headerkey', 'headervalue');
// part 2 sending the fetch request
return fetchJson(url, options).then(response =>
// part 3, converting the response and returning it
convertHTTPResponseToDataProvider(response, type, resource, params)
);
};
As the app has grown we ended up breaking it up into separate files so it's easier to read but it seems to be working out ok for us so far.
I had to install the redux browser tool and insert lots of logging statements to sort of step through it and get a better idea of what happens and when it happens. After getting the first action type/resource combo working it sort of clicked and adding to it since then has been pretty easy to figure out.