Is it possible to have multiple dataProviders in react-admin?

后端 未结 4 1676
半阙折子戏
半阙折子戏 2020-12-31 10:43

If I have multiple distinct REST API back-ends (separate apps doing separate things), and I want a single UI (react-admin-based) app that is capable of doing CRUD to entitie

相关标签:
4条回答
  • 2020-12-31 11:16

    In the README of recent ra release (3.4.1), there is a section (Extending a Data Provider (Example of File Upload)) that mentions: "... combine two Data Providers for two backends into a single object...". You can write a wrapper with branches to relay to different provider's implementation. An example to add your real data provider on top of their demo is:

    // new file dataProvider/super.js
    import simpleRestProvider from 'ra-data-simple-rest';
    import delayedDataProvider from './rest'
    
    const realDataProvider = simpleRestProvider('http://real_world_url/');
    
    const myDataProvider = {
        ...delayedDataProvider,
        getList: (resource, params) => {
            console.log(resource)
            if (["customers", "reviews", "commands"].includes(resource)) {
                // resources for the demo
                return delayedDataProvider.getList(resource, params)
            } else {
                // your own resources
                return realDataProvider.getList(resource, params)
            }
        },
    };
    
    export default myDataProvider;
    

    and replace the delayedDataProvider with the above myDataProvider

    // file dataProvider/index.js
             case 'graphql':
                 return import('./graphql').then(factory => factory.default());
             default:
    -            return import('./rest').then(provider => provider.default);
    +            return import('./super').then(provider => provider.default);
    

    Disclaimer: I got the same error as previous posts "provider is not function..."

    0 讨论(0)
  • 2020-12-31 11:21

    you can make custom of resource choose to which api you will use. one admin only have one dataProvider.

          <Admin
            dataProvider={superDataProvider}
         />
    

    but you can do like this:

     import superDataProvider from './dataProviderFactory';
    

    following is my code you can reference

    import dataProviderRuby from './dataProvider'; //handle ruby dataProvider
    import dataProviderJava from './dataProviderForJava';// handle java dataProvider
    import { rubyClient, javaClient } from './apolloClient';//custom two diff client one will fetch ruby service ,other will java
    
    const IsOmsResource = resource => {
      const omsReource = [
        'markets',
        'regions',
        'countries',
        'states',
        'items',
        'salesOrganizations',
      ];
      return omsReource.some(ele => ele === resource);
    }; //those resource will fetch data from java service others will go to ruby
    
    const rubyDataProvider = async (type, resource, params) => {
      const provider = await dataProviderRuby({
        client: rubyClient,
      });
      return provider(type, resource, params);
    };
    
    const javaDataProvider = async (type, resource, params) => {
      const provider = await dataProviderJava({
        client: javaClient,
      });
      return provider(type, resource, params);
    };
    
    const superDataProvider = (type, resource, params) => {
      if (IsOmsResource(resource)) {
        console.log('当前Java', resource);
        return javaDataProvider(type, resource, params);
      }
    
      console.log('当前ruby', resource);
      return rubyDataProvider(type, resource, params);
    };
    
    export default superDataProvider;
    

    following is the './apolloClient'

    import ApolloClient from 'apollo-client';
    import { createHttpLink } from 'apollo-link-http';
    import { InMemoryCache } from 'apollo-cache-inmemory';
    import { setContext } from 'apollo-link-context';
    
    const httpLinkRuby = createHttpLink({
      uri: '/graphql',
    });
    const httpLinkJava = createHttpLink({
      uri: '/oms-graphql',
    });
    const authLink = setContext((_, { headers }) => {
      const token = localStorage.getItem('token');
      return {
        headers: {
          ...headers,
          authorization: token ? `Bearer ${token}` : '',
        },
      };
    });
    export const rubyClient = new ApolloClient({
      link: httpLinkRuby,
      cache: new InMemoryCache(),
    });
    export const javaClient = new ApolloClient({
      link: authLink.concat(httpLinkJava),
      cache: new InMemoryCache(),
    });
    
    0 讨论(0)
  • 2020-12-31 11:23

    No, but you can have a super dataProvivder which would select the appropriate one depending on the resource. Something like:

    const dataProviders = [
        { dataProvider: simpleRestProvider('http://path.to.foo.api'), resources: ['foos'] },
        { dataProvider: simpleRestProvider('http://path.to.bar.api'), resources: ['bars'] },
    ];
    
    export default (type, resource, params) => {
        const dataProviderMapping = dataProviders.find(dp => dp.resources.includes(resource));
    
        return dataProviderMapping.dataProvider(type, resource, params);
    }
    
    0 讨论(0)
  • 2020-12-31 11:40

    React Admin 3 employs a new interface for dataProviders, and all answers seem to work only with React Admin 2.

    Here's what I did to make things work on React Admin 3:

    class CompositeDataProvider {
      constructor(dataProviders) {
        this.dataProviders = dataProviders;
      }
    
      _delegate(name, resource, params) {
        const { dataProvider } = this.dataProviders.find((dp) =>
          dp.resources.includes(resource)
        );
    
        return dataProvider[name](resource, params);
      }
    
      getList(resource, params) {
        return this._delegate("getList", resource, params);
      }
      getOne(resource, params) {
        return this._delegate("getOne", resource, params);
      }
      getMany(resource, params) {
        return this._delegate("getMany", resource, params);
      }
      getManyReference(resource, params) {
        return this._delegate("getManyReference", resource, params);
      }
      create(resource, params) {
        return this._delegate("create", resource, params);
      }
      update(resource, params) {
        return this._delegate("update", resource, params);
      }
      updateMany(resource, params) {
        return this._delegate("updateMany", resource, params);
      }
      delete(resource, params) {
        return this._delegate("delete", resource, params);
      }
      deleteMany(resource, params) {
        return this._delegate("deleteMany", resource, params);
      }
    }
    
    export default CompositeDataProvider;
    
    

    You can then use it in this way:

    const dataProvider = new compositeDataProvider([
      {
        dataProvider: jsonServerProvider("https://jsonplaceholder.typicode.com"),
        resources: ["posts", "users"],
      },
      {
        dataProvider: simpleRestProvider("http://path.to.bar.api"),
        resources: ["bars"],
      },
    ]);
    

    It's still barebones but it gives you an idea you can improve on.

    0 讨论(0)
提交回复
热议问题