ra-data-feathers icon indicating copy to clipboard operation
ra-data-feathers copied to clipboard

[docs] How to decorate the `ra-data-feathers` data provider

Open strarsis opened this issue 2 years ago • 4 comments

The ra-data-feather provider can't be decorated (for extending or changing its behavior) the usual way (as the example in the react-admin does). The reason is that the ra-data-feather provider returns a function instead of a JavaScript object with member methods.

That function needs to be wrapped by a decorator function:

import { UPDATE } from 'react-admin';

const addUploadCapabilities = function (dataProvider) {
    return function(type, resource, params) {

        // e.g. for "categories" resource and "UPDATE" type only:
        if(resource === 'categories' && type === UPDATE) {
            // extra stuff, modify `params`/`resource`
            // [...]
            // return [...]; // return to completely skip the `dataProvider` in this case
        }

        // call the underlying `ra-data-feathers` provider
        return dataProvider(type, resource, params);
    }
}

strarsis avatar Mar 12 '22 22:03 strarsis

A simple way to do it, it is after getting the dataProvider.

import feathersClient from './feathersClient';
import { restClient, authClient } from 'ra-data-feathers';
const restClientOptions = {}; 
const dataProvider = restClient(feathersClient, restClientOptions); 

josx avatar Mar 15 '22 14:03 josx

@josx: Thanks, but the 2nd code excerpt in your post is incorrectly formatted and doesn't render.

strarsis avatar Mar 15 '22 19:03 strarsis

I deleted the 2nd excerpt, was a typo.

Just with above lines and following this https://marmelab.com/react-admin/DataProviders.html#extending-a-data-provider-example-of-file-upload you can do it.

The idea is getting an instance of the provider and then extending.

josx avatar Mar 15 '22 19:03 josx

@josx: Using the approach in the docs results in an error:

Error: Unknown dataProvider function: getList

The reason is that the ra-data-feathers data provider isn't a JavaScript object but rather a function, hence the member method getList cannot be found.

const dataProvider = restClient(feathersClient, restClientOptions);

const myDataProvider = {
    ...dataProvider,
    update: (resource, params) => {
        if (resource !== 'posts' || !params.data.pictures) {
            // fallback to the default implementation
            return dataProvider.update(resource, params);
        }
        /**
         * For posts update only, convert uploaded image in base 64 and attach it to
         * the `picture` sent property, with `src` and `title` attributes.
         */
        
        // Freshly dropped pictures are File objects and must be converted to base64 strings
        const newPictures = params.data.pictures.filter(
            p => p.rawFile instanceof File
        );
        const formerPictures = params.data.pictures.filter(
            p => !(p.rawFile instanceof File)
        );

        return Promise.all(newPictures.map(convertFileToBase64))
            .then(base64Pictures =>
                base64Pictures.map(picture64 => ({
                    src: picture64,
                    title: `${params.data.title}`,
                }))
            )
            .then(transformedNewPictures =>
                dataProvider.update(resource, {
                    ...params,
                    data: {
                        ...params.data,
                        pictures: [
                            ...transformedNewPictures,
                            ...formerPictures,
                        ],
                    },
                })
            );
    },
};


const authProvider = authClient(feathersClient, authClientOptions);

render(
    <React.StrictMode>
          <Admin
              dataProvider={myDataProvider}
[...]

Treating the ra-data-feathers data provider as a function however works:

const addUploadCapabilities = function (dataProvider) {
    return function(type, resource, params) {

        // e.g. for "categories" resource and "UPDATE" type only:
        if(resource === 'categories' && type === UPDATE) {
            // extra stuff, modify `params`/`resource`
            // [...]
            // return [...]; // return to completely skip the `dataProvider` in this case
        }

        // call the underlying `ra-data-feathers` provider
        return dataProvider(type, resource, params);
    }
}

strarsis avatar Mar 15 '22 20:03 strarsis