Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Admin - how to call dataProvider with nested path like abc/def

React-admin's Resource component maps name prop value to an endpoint.

E.g. to access data from . http://example.com/abc, your Resource component looks like this: <Resource name='abc'/>

What i want to access resource at http://example.com/abc/def? This <Resource name='abc/def'/> doesn't even call the dataProvider function.

I wouldn't want to end up with ugly solution like:

// App.js
<Resource name='def'/>

// dataProvider.js
if (resource==='def') {
url = 'abc/def'
}

Do resources names always have to be without /? Any hacks?

like image 937
Sebastian Avatar asked May 18 '18 15:05

Sebastian


1 Answers

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

  1. 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)
  2. fetch request/api call is sent (sending the request)
  3. 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.

like image 131
Joseph Wilson Avatar answered Oct 16 '22 22:10

Joseph Wilson