#refineweek: Setting Up the Client App
Tags: refineweek, webdev, javascript, react
Published: 2023-02-15 10:12:41



![day description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/heo1yuvfsmw7u3r4wrc8.png)


In this episode, we initialize our **Pixels** app using [**refine**](https://github.com/refinedev/refine) and get familiar with the boilerplate code to be created with the `create refine-app` CLI tool.

This is Day 2 of the [**refineWeek**](https://refine.dev/week-of-refine/) series. **refineWeek** is a seven-part tutorial that aims to help developers learn the ins-and-outs of **refine**'s powerful capabilities and get going with **refine** within a week.

### refineWeek series
- Day 1 - [Pilot & refine architecture](https://dev.to/refine/refineweek-pilot-refine-architecture-dg3)


## Overview

In the previous post, we got a preview of **refine**'s underlying architecture, especially on how **refine**'s core modules abstract and divide an app's logic inside individual providers and allow their methods to be easily accessed and executed with hooks from inside consumer components. This abstraction at the providers layer is where **refine** shines and require extensive configuration to begin with.

In this part, we will get into the details of two important providers: namely, the [`dataProvider`](https://refine.dev/docs/tutorial/understanding-dataprovider/index/) and [`authProvider`](https://refine.dev/docs/tutorial/understanding-authprovider/index/) props of our [`<Refine />`](http://localhost:3000/docs/api-reference/core/components/refine-config/) component. We will be building on this knowledge in the coming episodes.

The providers will be generated by the `create refine-app` CLI tool based on our choice, so we'll start off with setting up the **Pixels** app right away.


## Project Setup

For this project, we are using a PostgreSQL database hosted in the [**Supabase**](https://supabase.com/) cloud. **refine** comes with an optional package for **Supabase** that gives us `dataProvider` and `authProvider`s out-of-the-box for handling requests for CRUD actions, authentication and authorization against models hosted in a **Supabase** server.

We are going to include **refine**'s Ant Design package for the UI side.

Let's go ahead and use the `create refine-app` CLI tool to interactively initialize the project. Navigate to a folder of your choice and run:



```bash
npm create refine-app@latest pixels
```

`create refine-app` presents us with a set of questions for choosing the libraries and frameworks we want to work with. We'll initialize a **refine** project with `craco` to manage our configurations. Other important things are to be able to customize our **Ant Design** theme and layout.  

So, I chose the following options:



```bash
✔ Choose a project template · refine(CRA)
✔ What would you like to name your project?: · pixels
✔ Choose your backend service to connect: · Supabase
✔ Do you want to use a UI Framework?: · Ant Design
✔ Do you want to add example pages?: · no
✔ Do you want to add dark mode support?: · no
✔ Do you want to customize the Ant Design layout?: · yes
✔ Do you need i18n (Internationalization) support?: · no
✔ Do you want to add kbar command interface support?: · no
✔ Would you mind sending us your choices so that we can improve superplate? · yes
```

This should create a rudimentary **refine** app that supports [**Ant Design**](https://ant.design/) in the UI and [**Supabase**](https://supabase.com/) in the backend. If we open the app in our code editor, we can see that **refine**'s optional packages for **Ant Design** and **Supabase** are added to `package.json`:

```json 
// package.json

"dependencies": {
  "@pankod/refine-antd": "^4.7.0",
  "@pankod/refine-core": "^3.18.0",
  "@pankod/refine-react-router-v6": "^3.18.0",
  "@pankod/refine-supabase": "^3.18.0",
}
```

We are going to use **Ant Design** components for our UI thanks to the `@pankod/refine-antd` module. `@pankod/refine-supabase` module allows us to use **refine**'s **Supabase** auth and data providers.

We'll cover these **Supabase** related providers as we add features to our app in the upcoming episodes. However, let's try building the app for now, and check what we have in the browser after running the development server. In the terminal, run the following command:

```bash
npm run dev
```

After that, navigate to `http://localhost:3000`, and lo and behold! we have a **refine** app:



<div class="img-container">
    <div class="window">
        <div class="control red"></div>
        <div class="control orange"></div>
        <div class="control green"></div>
    </div>
   <img src="https://refine.ams3.cdn.digitaloceanspaces.com/blog/2023-02-05-refine-pixels-2/welcome.png
"  alt="react crud app welcome" />

</div>

<br />



## Exploring the App

Let's now see what **refine** scaffolded for us during initialization.

Our main point of focus is the `src` folder. And for now, especially the `<App />` component.

If we look inside the `App.tsx` file, we can see a `<Refine />` component crowded with passed in **props**:

```ts
// src/App.tsx

import React from "react";
import { Refine } from "@pankod/refine-core";
import {
    AuthPage,
    notificationProvider,
    ReadyPage,
    ErrorComponent,
} from "@pankod/refine-antd";
import "@pankod/refine-antd/dist/reset.css";

import { dataProvider, liveProvider } from "@pankod/refine-supabase";
import routerProvider from "@pankod/refine-react-router-v6";
import { supabaseClient } from "utility";
import { Layout } from "components/layout";
import authProvider from "./authProvider";

function App() {
    return (
        <Refine
            dataProvider={dataProvider(supabaseClient)}
            liveProvider={liveProvider(supabaseClient)}
            authProvider={authProvider}
            routerProvider={{
                ...routerProvider,
                routes: [
                    {
                        path: "/register",
                        element: <AuthPage type="register" />,
                    },
                    {
                        path: "/forgot-password",
                        element: <AuthPage type="forgotPassword" />,
                    },
                    {
                        path: "/update-password",
                        element: <AuthPage type="updatePassword" />,
                    },
                ],
            }}
            LoginPage={() => (
                <AuthPage
                    type="login"
                    providers={[
                        {
                            name: "google",
                            label: "Sign in with Google",
                        },
                    ]}
                    formProps={{
                        initialValues: {
                            email: "info@refine.dev",
                            password: "refine-supabase",
                        },
                    }}
                />
            )}
            notificationProvider={notificationProvider}
            ReadyPage={ReadyPage}
            catchAll={<ErrorComponent />}
            Layout={Layout}
        />
    );
}

export default App;
```

Today, we'll examine a few of these props so that we are ready to move to the next episode.


### The `<Refine />` Component

The [`<Refine />`](http://localhost:3000/docs/api-reference/core/components/refine-config/) component is the entry point of a **refine** app. In order to leverage the power of **refine**'s abstraction layers, we need to have the `<Refine />` component.

Then we have to configure the `<Refine />` component with the provider objects we want to use in our app. We can see that `create refine-app` already added the props for us inside `<Refine />` out-of-the-box.  

We will be using them in our **Pixels** app. Some provider objects like the `routerProvider` or the `dataProvider` are defined for us by **refine**'s core or support modules and some like the `accessControlProvider` have to be defined by ourselves.


### `<Refine />`'s `dataProvider` Prop

[**refine**'s **data provider**](https://refine.dev/docs/tutorial/understanding-dataprovider/index/) is the context which allows the app to communicate with a backend API via a `HTTP` client. It subsequently makes response data returned from HTTP requests available to consumer components via a set of **refine** data hooks.

If we look closely, our `dataProvider` prop derives a value from a call to `dataProvider(supabaseClient)`:

```tsx
// src/App.tsx

dataProvider={dataProvider(supabaseClient)}
```

The returned object, also called the **`dataProvider`** object, has the following signature:



```tsx
const dataProvider = {
    create: ({ resource, variables, metaData }) => Promise,
    createMany: ({ resource, variables, metaData }) => Promise,
    deleteOne: ({ resource, id, variables, metaData }) => Promise,
    deleteMany: ({ resource, ids, variables, metaData }) => Promise,
    getList: ({
        resource,
        pagination,
        hasPagination,
        sort,
        filters,
        metaData,
    }) => Promise,
    getMany: ({ resource, ids, metaData }) => Promise,
    getOne: ({ resource, id, metaData }) => Promise,
    update: ({ resource, id, variables, metaData }) => Promise,
    updateMany: ({ resource, ids, variables, metaData }) => Promise,
    custom: ({
        url,
        method,
        sort,
        filters,
        payload,
        query,
        headers,
        metaData,
    }) => Promise,
    getApiUrl: () => "",
};

```


Each item in this object is a method that has to be defined by us or **refine**'s packages.

**refine** supports [15+ backend](https://refine.dev/integrations/) `dataProvider` integrations as optional packages that come with distinct definitions of these methods that handle CRUD operations according to their underlying architectures. The full list can be found [here](https://refine.dev/docs/packages/list-of-packages/#data-provider-packages).

Normally, for our own backend API, we have to define each method we need for sending `http` requests inside a `dataProvider` object as above. But since we are using the [`@pankod/refine-supabase`](https://github.com/refinedev/refine/tree/master/packages/supabase) package, `dataProvider={dataProvider(supabaseClient)}` makes the following object available to us:

[@pankod/refine-supabase/src/index.ts](https://github.com/refinedev/refine/blob/master/packages/supabase/src/index.ts)



We don't have to get into the mind of the people at **refine** yet, but if we skim over closely, the `dataProvider` object above has pretty much every method we need to perform all CRUD operations against a **Supabase** database. Notable methods we are going to use in our app are: `create()`, `getOne()`, `getList()` and `update()`.

For the details of how these methods work, please take your time to scan through the [`dataProvider` API reference](https://refine.dev/docs/api-reference/core/providers/data-provider/).


In order to get the **Supabase** `dataProvider` object to deliver, first a `supabaseClient` has to be set up.


### **refine**'s `supabaseClient`

If we look inside `src/utility/`, we have a `supabaseClient.ts` file containing the credentials of a client that provides us access to a **Supabase** backend:

```ts
//src/utility/supabaseClient.ts

import { createClient } from "@pankod/refine-supabase";

const SUPABASE_URL = "https://ifbdnkfqbypnkmwcfdes.supabase.co";
const SUPABASE_KEY =
    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImlmYmRua2ZxYnlwbmttd2NmZGVzIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NzA5MTgzOTEsImV4cCI6MTk4NjQ5NDM5MX0.ThQ40H-xay-Hi5cf7H9mKccMCvAX3iCvYVJDe0KiHtw";

export const supabaseClient = createClient(SUPABASE_URL, SUPABASE_KEY, {
    db: {
        schema: "public",
    },
    auth: {
        persistSession: true,
    },
});
```

This file was also generated for us by `create refine-app` using **refine**'s **Supabase** package.

Inside `<Refine />` component, we are getting the value of the `dataProvider` prop by passing in `supabaseClient` to the `dataProvider()` function imported from this package:

```tsx 
// title="App.tsx"

dataProvider={dataProvider(supabaseClient)}
```

We need to tweak the `supabaseClient.ts` file with our own credentials, which we will do when we add `resources` to our app.

If we inspect further, setting up **Supabase** with **refine** helps us enable not only the `dataProvider` prop, but also the `authProvider` and `liveProvider` props inside `<Refine />`. This is because they all depend on `supabaseClient` to send `http` requests. We'll explore the `liveProvider` prop on Day 4, but let's also look at the `authProvider` here to enhance our understanding.


### `<Refine />`'s `authProvider` Prop

We can clearly see in our `<Refine />` component that `create refine-app` already enabled the `authProvider` prop by passing in the corresponding object for us:

```ts
// title="App.tsx"
authProvider={authProvider}
```

Earlier on, the `authProvider` object was already created by `create refine-app` inside the `authProvider.ts` file:


```ts
// src/authProvider.ts

import { AuthProvider } from "@pankod/refine-core";
import { supabaseClient } from "utility";

export const authProvider: AuthProvider = {
    login: async ({ email, password, providerName }) => {
        // sign in with oauth
        if (providerName) {
            const { data, error } = await supabaseClient.auth.signInWithOAuth({
                provider: providerName,
            });

            if (error) {
                return Promise.reject(error);
            }

            if (data?.url) {
                return Promise.resolve();
            }
        }

        // sign in with email and password
        const { data, error } = await supabaseClient.auth.signInWithPassword({
            email,
            password,
        });

        if (error) {
            return Promise.reject(error);
        }

        if (data?.user) {
            return Promise.resolve();
        }

        // for third-party login
        return Promise.resolve(false);
    },
    register: async ({ email, password }) => {
        const { data, error } = await supabaseClient.auth.signUp({
            email,
            password,
        });

        if (error) {
            return Promise.reject(error);
        }

        if (data) {
            return Promise.resolve();
        }
    },
    forgotPassword: async ({ email }) => {
        const { data, error } = await supabaseClient.auth.resetPasswordForEmail(
            email,
            {
                redirectTo: `${window.location.origin}/update-password`,
            },
        );

        if (error) {
            return Promise.reject(error);
        }

        if (data) {
            return Promise.resolve();
        }
    },
    updatePassword: async ({ password }) => {
        const { data, error } = await supabaseClient.auth.updateUser({
            password,
        });

        if (error) {
            return Promise.reject(error);
        }

        if (data) {
            return Promise.resolve("/");
        }
    },
    logout: async () => {
        const { error } = await supabaseClient.auth.signOut();

        if (error) {
            return Promise.reject(error);
        }

        return Promise.resolve("/");
    },
    checkError: () => Promise.resolve(),
    checkAuth: async () => {
        await supabaseClient.auth.getSession();
        return Promise.resolve();
    },
    getPermissions: async () => {
        const { data } = await supabaseClient.auth.getUser();
        const { user } = data;

        if (user) {
            return Promise.resolve(user.role);
        }
    },
    getUserIdentity: async () => {
        const { data } = await supabaseClient.auth.getUser();
        const { user } = data;

        if (user) {
            return Promise.resolve({
                ...user,
                name: user.email,
            });
        }

        return Promise.reject();
    },
};
```



This object has all the methods we need to implement an email / password based authentication and authorization system in our app.

Notice, as mentioned before, that `authProvider` relies on `supabaseClient` to connect to our **Supabase** database. So, in this case, our `authoProvider` was generated as part of the **Supabase** package.

As we can infer by now, although we have stated that **refine** performs and manages a lot of heavylifting and simplifies the app logic by dividing concerns into separate contexts, providers and hooks, _configuring_ all these providers is a heavy task itself.

It, fortunately, makes configuration easier by composing individual providers inside a single object.

These are pretty much the essentials we should get familiar with in order to accept the invitation to add `resources` to the `<Refine />` component.

## Summary

In this post, we went through the process of initializing our **Pixels** app with a **Supabase** hosted PostgreSQL database and **Ant Design** UI framework.

We then explored the boilerplate code created by `create refine-app` using **refine**'s **Supabase** support package, especially the files related to `dataProvider` and `authProvider` props of the `<Refine />` component. We touched on setting `supabaseClient` which is used by these providers to send HTTP requests to the **Supabase** backend.

In the next article, we will use these providers to implement RESTful CRUD actions for creating a canvas, showing a canvas, drawing pixels on it and showing a public gallery that lists canvases. We will also add authentication to our app.