Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The dataProvider is probably wrong for 'GET_LIST'

I'm trying to use react-admin with hasura adapter. When i try to use the cruds, the error

The response to 'GET_LIST' must be like { data: ... }, but the received response does not have a 'data' key.

The authentication is working fine, but i can't see any request for query the "associado" data. Only the AUTH_CHECK request are launched, and no graphql request for the "associado" table. The error are throwed without any request made. What's wrong?

File for CRUD associado:

import React from 'react';
import { List, Datagrid, TextField, Show, SimpleShowLayout, DateField } from 'react-admin';

export function AssociadoList(props) {
    return (
        <List {...props}>
            <Datagrid>
                <TextField source="nome" />
                <DateField source="data_aniversario" />
                {/*<ReferenceField label="Endereço" source="enderecoId" reference="enderecos">
                <TextField source="bairro" />
                <TextField source="bairro" />
            </ReferenceField>*/}
            </Datagrid>
        </List>
    )
};

export function AssociadoShow(props) {
    return (
        <Show {...props}>
            <SimpleShowLayout>
                <TextField source="nome" />
                <DateField source="data_aniversario" />
            </SimpleShowLayout>
        </Show>
    )
};

The auth provider:

import { AUTH_LOGIN, AUTH_LOGOUT, AUTH_ERROR, AUTH_CHECK } from 'react-admin';
import graphql from './graphqlClient';
import Cookies from 'universal-cookie';
import { GraphQLClient } from 'graphql-request';

const cookies = new Cookies();

const LOGIN = `
    mutation($username:String!, $password:String!){
        login(username: $username, password: $password){
            token
        }
    }
`;
const ME = `
    query {
        me {
            username
        }
    }
`;

export default (type, params) => {

    if (type === AUTH_LOGIN) {
        const { username, password } = params;
        return graphql.request(LOGIN, { username, password }).then(data => {
            const token = data.login.token;
            cookies.set("authToken", token, { path: "/", sameSite: "strict" });
        });
    }
    if (type === AUTH_LOGOUT) {
        cookies.remove("authToken", { path: "/", sameSite: "strict" });
        return Promise.resolve();
    }
    if (type === AUTH_ERROR) {
        const graphqlauth = new GraphQLClient(process.env.REACT_APP_HASURA_ENDPOINT, {
            headers: {
                authorization: 'Bearer ' + cookies.get('authToken'),
            },
        })
        return graphqlauth.request(ME).then(data => { return (data.me.username) ? Promise.resolve() : Promise.reject(); }).catch(e => {
            cookies.remove("authToken", { path: "/", sameSite: "strict" });

        });

    }
    if (type === AUTH_CHECK) {
        return cookies.get('authToken') ? Promise.resolve() : Promise.reject();
    }
    return Promise.resolve();
};

and the App.js;

import React from 'react';
import { Admin, Resource } from 'react-admin';
import Dashboard from './Dashboard';
import hasuraDataProvider from 'ra-data-hasura';
import authProvider from './authProvider';
import Cookies from 'universal-cookie';
import { AssociadoList, AssociadoShow } from "./Associado";
import portugueseMessages from 'ra-language-portuguese'


const dataProvider = function () {

  const cookies = new Cookies();
  const dataProvider = hasuraDataProvider(process.env.REACT_APP_HASURA_URL, { "content-type": "application/json", "Authorization": "Bearer " + cookies.get("AuthToken") });
  return dataProvider;
}
const messages = {
  'pt': portugueseMessages,
};
const i18nProvider = locale => messages[locale];
function App() {
  return (
    <Admin
      dataProvider={dataProvider}
      authProvider={authProvider}
      dashboard={Dashboard}
      locale="pt" i18nProvider={i18nProvider}
    >
      <Resource name="adear.associado" list={AssociadoList} options={{ label: 'Associado' }} show={AssociadoShow} />
    </Admin>
  );
}

export default App;

Here is my package.json

{
  "name": "dashboard",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "graphql-request": "^1.8.2",
    "ra-data-hasura": "^0.0.6",
    "ra-language-portuguese": "^1.5.1",
    "react": "^16.8.6",
    "react-admin": "2.9.5",
    "react-cookie": "^4.0.1",
    "react-dom": "^16.8.6",
    "react-scripts": "3.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
like image 981
Mihael Zamin Avatar asked Dec 09 '25 09:12

Mihael Zamin


2 Answers

My take is that you have a small issue with your custom dataProvider.

You are trying to enhance the hasura data provider, but by doing so, you are introducing a small bug.

import React from 'react';
import { Admin, Resource } from 'react-admin';
import Dashboard from './Dashboard';
import hasuraDataProvider from 'ra-data-hasura';
import authProvider from './authProvider';
import Cookies from 'universal-cookie';
import { AssociadoList, AssociadoShow } from "./Associado";
import portugueseMessages from 'ra-language-portuguese'


const dataProvider = function () {
  const cookies = new Cookies();
  // hasuraDataProvider is a factory, which returns a function
  const dataProvider = hasuraDataProvider(process.env.REACT_APP_HASURA_URL, { "content-type": "application/json", "Authorization": "Bearer " + cookies.get("AuthToken") });
  return dataProvider; // Here you are returning the real dataprovider
}

const messages = {
  'pt': portugueseMessages,
};

const i18nProvider = locale => messages[locale];

function App() {
  return (
    <Admin
      {/* dataProvider is a function which returns the hasura dataProvider, but React Admin expects to get your function results instead! */}
      dataProvider={dataProvider}
      authProvider={authProvider}
      dashboard={Dashboard}
      locale="pt" i18nProvider={i18nProvider}
    >
      <Resource name="adear.associado" list={AssociadoList} options={{ label: 'Associado' }} show={AssociadoShow} />
    </Admin>
  );
}

export default App;

IMHO, the fix is as simple as calling your dataProvider function when passing the prop to the admin.

-    dataProvider={dataProvider}
+    dataProvider={dataProvider()}
like image 133
Kmaschta Avatar answered Dec 10 '25 21:12

Kmaschta


I found the answer. To make work, you need to pass the authorization token as a parameter in the dataProvider function wrapper, and using react-cookie, you can use all the power of states and React Hooks. It's like magic:

import React from 'react';
import { Admin, Resource } from 'react-admin';
import Dashboard from './Dashboard';
import hasuraDataProvider from 'ra-data-hasura';
import authProvider from './authProvider';
import {useCookies} from "react-cookie";
import { AssociadoList, AssociadoShow } from "./Associado";
import portugueseMessages from 'ra-language-portuguese'


const dataProvider = function (authToken) {
  const dataProvider = hasuraDataProvider("http://localhost:8080", { "content-type": "application/json", "Authorization": "Bearer " +  authToken});
  return dataProvider;
}
const messages = {
  'pt': portugueseMessages,
};
const i18nProvider = locale => messages[locale];
function App() {
  const [cookies] = useCookies(['authToken']);
  return (
    <Admin
      dataProvider={dataProvider(cookies.authToken)}
      authProvider={authProvider}
      dashboard={Dashboard}
      locale="pt" i18nProvider={i18nProvider}
    >
      <Resource name="adear.associado" list={AssociadoList} options={{ label: 'Associado' }} show={AssociadoShow} />
    </Admin>
  );
}

export default App;

like image 35
Mihael Zamin Avatar answered Dec 10 '25 23:12

Mihael Zamin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!