magic-amber
magic-amber7mo ago

Custom data provider with JWT and specific request types

Hi, I'm quite a noob with refine and react. I want to create a custom data provider, which will connect to my backend (rest api). I handle authentication with JWTs, so each request should include that. Any help is greatly appreciated, thanks!
14 Replies
kapa.ai
kapa.ai7mo ago
Hi @Achilleas. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Sure, I can guide you through the process of creating a custom data provider with JWT authentication for your REST API. Firstly, you need to customize the data provider to work with your REST API. You can use the swizzle command to customize the data provider. Here are the steps: 1. Run the swizzle command in the project directory:
npm run refine swizzle
npm run refine swizzle
2. Select @refinedev/simple-rest from the list of available data providers. 3. Edit the /rest-data-provider/index.ts file to customize the data provider. 4. Pass the customized data provider to the dataProvider prop of the Refine component.
import { Refine } from "@refinedev/core";
import { dataProvider } from "./rest-data-provider";

const App = () => {
return (
<Refine
dataProvider={dataProvider}
/* ... */
/>
);
};
import { Refine } from "@refinedev/core";
import { dataProvider } from "./rest-data-provider";

const App = () => {
return (
<Refine
dataProvider={dataProvider}
/* ... */
/>
);
};
(Source: refine.dev (https://refine.dev/docs/data/packages/simple-rest#customizing-the-data-provider-)) For JWT authentication, you can create a custom fetcher for the requests and handle the authentication logic there. When creating a GraphQL Client, you can pass a fetch function to the client options. This function will be used to append the authentication headers to the requests. Here is an example:
import graphqlDataProvider, { GraphQLClient } from "@refinedev/graphql";

const client = new GraphQLClient(API_URL, {
fetch: (url: string, options: RequestInit) => {
return fetch(url, {
...options,
headers: {
...options.headers,
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
});
},
});

const dataProvider = graphqlDataProvider(client);
import graphqlDataProvider, { GraphQLClient } from "@refinedev/graphql";

const client = new GraphQLClient(API_URL, {
fetch: (url: string, options: RequestInit) => {
return fetch(url, {
...options,
headers: {
...options.headers,
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
});
},
});

const dataProvider = graphqlDataProvider(client);
(Source: refine.dev (https://refine.dev/docs/data/packages/graphql#authentication)) Please note that the above example uses GraphQL, but the concept is the same for REST. You just need to replace the GraphQL client with your REST client. For more detailed information on creating a custom data provider, you can refer to the "Create Data Provider From Scratch" section in the tutorial (https://refine.dev/docs/tutorial/understanding-dataprovider/create-dataprovider/). For handling custom request types, you can refer to the custom method in the Refine documentation (https://refine.dev/docs/tutorial/understanding-dataprovider/create-dataprovider#custom). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai7mo ago
<@340075856703520768> kapa.ai is still learning and improving, please let us know how it did by reacting below
magic-amber
magic-amber7mo ago
@kapa.ai Is it necessary to use the rest-data-provider? Can't I use the "DataProvider" from "@refinedev/core"
kapa.ai
kapa.ai7mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Yes, you can definitely use the DataProvider from @refinedev/core to create your custom data provider. The DataProvider interface provides a set of methods that correspond to the CRUD operations and more. You can implement these methods according to your API's specifications. Here's a basic example of how you can create a custom data provider:
import { DataProvider } from "@refinedev/core";

const dataProvider: DataProvider = {
getList: (resource, params) => { /* implement according to your API */ },
getOne: (resource, params) => { /* implement according to your API */ },
getMany: (resource, params) => { /* implement according to your API */ },
getManyReference: (resource, params) => { /* implement according to your API */ },
create: (resource, params) => { /* implement according to your API */ },
update: (resource, params) => { /* implement according to your API */ },
updateMany: (resource, params) => { /* implement according to your API */ },
delete: (resource, params) => { /* implement according to your API */ },
deleteMany: (resource, params) => { /* implement according to your API */ },
custom: (resource, params) => { /* implement according to your API */ },
};

export default dataProvider;
import { DataProvider } from "@refinedev/core";

const dataProvider: DataProvider = {
getList: (resource, params) => { /* implement according to your API */ },
getOne: (resource, params) => { /* implement according to your API */ },
getMany: (resource, params) => { /* implement according to your API */ },
getManyReference: (resource, params) => { /* implement according to your API */ },
create: (resource, params) => { /* implement according to your API */ },
update: (resource, params) => { /* implement according to your API */ },
updateMany: (resource, params) => { /* implement according to your API */ },
delete: (resource, params) => { /* implement according to your API */ },
deleteMany: (resource, params) => { /* implement according to your API */ },
custom: (resource, params) => { /* implement according to your API */ },
};

export default dataProvider;
Then, you can use this custom data provider in your Refine component:
import { Refine } from "@refinedev/core";
import dataProvider from "./custom-data-provider";

const App = () => {
return (
<Refine
dataProvider={dataProvider}
/* ... */
/>
);
};
import { Refine } from "@refinedev/core";
import dataProvider from "./custom-data-provider";

const App = () => {
return (
<Refine
dataProvider={dataProvider}
/* ... */
/>
);
};
Remember to replace the /* implement according to your API */ comments with your actual API calls. You can use any HTTP client like fetch or axios to make these calls. Don't forget to include the JWT in the headers of your requests for authentication. For more information on creating a custom data provider, you can refer to the "Create Data Provider From Scratch" section in the tutorial (https://refine.dev/docs/tutorial/understanding-dataprovider/create-dataprovider/). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai7mo ago
<@340075856703520768> kapa.ai is still learning and improving, please let us know how it did by reacting below
rising-crimson
rising-crimson7mo ago
Hi I am also struggling with that (Express REST API with JWT) Let me know if you find smthg. I ll also update in case I find...
magic-amber
magic-amber7mo ago
Will do, and thanks!
wise-white
wise-white7mo ago
Hello folks, for fetching data wuth authentication, please check: https://refine.dev/docs/guides-concepts/data-fetching/#authentication-
Data Fetching | refine
Data is essential for any UI Application and these applications are a bridge between users and the underlying data source(s), making it possible for users to interact with data in a meaningful way.
rising-crimson
rising-crimson7mo ago
Ok the main issue I had and solved is that my database had some funky id... like CityId - Renaming to "id" all of the ids solved my issues- not sure it will help but just updating...
magic-amber
magic-amber7mo ago
I see, and on your backend the methods you had for CRUD were POST, GET, PUT, DELETE?
rising-crimson
rising-crimson7mo ago
yes I have also added Patch
magic-amber
magic-amber7mo ago
Instead of PUT or for somethign else?
rising-crimson
rising-crimson7mo ago
// POST - Create FaultType router.post('/', async (req, res) => { // GET - Read all FaultTypes router.get('/', async (req, res) => { try { // GET - Read single FaultType router.get('/:id', async (req, res) => { // PUT - Update FaultType router.put('/:id', async (req, res) => { // PATCH - Partially Update FaultType router.patch('/:id', async (req, res) => { // DELETE - Delete FaultType router.delete('/:id', async (req, res) => { Those are the 6 I have implemented so far... Did you find how to manage the JWT?
magic-amber
magic-amber7mo ago
Just gonna use plain JS for now 🙃