Refine.dev and useGenerated.com - business apps extremely fast
Tags: graphql, prisma, refine, nestjs
Published: 2023-06-13 14:26:54

## What is [Refine.dev](https://refine.dev/) ?

Open-source enterprise application framework - it allows you to build business apps and admin panels in React extremely fast.

A React-admin alternative.

Cool part about it is that it **auto-generates React code as one would have written by hand**. This approach is extremely productive and flexible. 

The generated code is in Material UI, Ant Design, ChakraUI, Mantine or headless/you own custom.


## What is [useGenerated.com ](https://useGenerated.com) ?

A CLI that auto-generates a CRUD NestJS, Prisma ORM, GraphQL API in minutes.

1. Define the database models in Prisma ORM.
2. Describe your API, query depth, authorization/ authentication in **a simple configuration file**.
3. Run a CLI command. Congrats! you have a GraphQL CRUD API, as nested as you want, with filter and sort for nested queries.
4. **Customize, extend anything **from the output. You are in full control. The output is code as you(or me) would have written.

### Sounds like a good match right ?

It absolutely is! They both give you the speed of a framework but full flexibility as you would have written it from scratch, because of their approach auto-generate code as the "hand written one".

### Enough talk! let's code

Go to [useGenerated.com ](https://useGenerated.com) and use the code EGDCONX to get it free (limited offer). Download and extract the content.


##  Getting started with the backend - Initial setup 

1. Create a NestJs App

`npm i -g @nestjs/cli`
`nest new project-name`


2. replace the package.json with the one received with this module

3. Add the use-generated folder at the same level as the NestJs app and run yarn or npm install

4. Run `yarn use-generated init`

If everything worked well you should now have a `\use-generated-config` folder created at the root level. Your app should look like [this](https://github.com/usegen/use-generated-demo-1/tree/dd4e5d35fc457d1a375e575016ea53f28abed322)

For this example we will only change `appconfig.json` from that folder.


###  First DB models

Have a `.env` file that points to a postgress db like this. (keep the other 2 variables with random strings we'll talk about that later)

```
DATABASE_URL="postgresql://johndoe:randompass@localhost:5432/mydb?schema=public"

SALT ="0bsfe607f676ee7cfd9678580b86f501be8cbf5cb04174e2"
JWT_SECRET = "32472YKJHDfdfsdkasjhdjwu.fvfdfd"
```

 Add the following DB models in `prisma/schema.prisma` file 

```
model BlogPost {
  id        Int       @id @default(autoincrement())
  title     String
  content   String?
  published Boolean
  authorId  Int?
  author    User?     @relation(fields: [authorId], references: [id])
  comments  Comment[]
}

model Comment {
  id       Int      @id @default(autoincrement())
  content  String
  authorId Int?
  author   User?    @relation(fields: [authorId], references: [id])
  postId   Int
  post     BlogPost @relation(fields: [postId], references: [id])
}

model User {
  id           Int        @id @default(autoincrement())
  email        String     @unique
  passwordHash String
  age          String?
  resetToken   String?    @unique
  roles        UserRole[]
  comments     Comment[]
  posts        BlogPost[]
}

enum UserRole {
  AuthenticatedUser
  Admin
  SuperAdmin
}

```

Run `yarn prisma generate` and `yarn prisma  migrate dev`.
 
It generates the Prisma client and the db migrations, you will need to run this commands every time `prisma/schema.prisma` file changes.

If this doesn't look familiar please take a look at [prisma ORM](https://www.prisma.io/)

Let's configure now how the backend app should be structred and how the GraphQL api will look like.
Go to   `appconfig.json` and add the following to the modules property
```json
...
  "modules": [{
      "name": "user",
      "models": [
        {
          "name": "User",
          "queryDepthLevel":1
        }
      ]
    },
    {
      "name": "post",
      "models": [
        {
          "queryDepthLevel":2,
          "name": "BlogPost"
        },
        {
          "name": "Comment",
          "queryDepthLevel":2
        } 
      ]
    }],
...
```
Modules will be the folder structure and the NestJS modules.

`queryDepthLevel` defines how many levesl can the queries be for that specific resource / model. it can also be configured at the root level with `defaultQueryDepthLevel`


**Run `yarn use-generated api`. Congrats! you just created a GraphQL API**

the code should look like [this](https://github.com/usegen/use-generated-demo-1/tree/7135a4ec0374206c423e7b268ab57b6bb7aa8c14)

run `yarn start:dev`, navigate to  http://localhost:3000/graphql and check that the API is working 

Change the port of the application to 3001 so that the frontend can use the 3000. you can do that in `src/main.ts`
line 6 :`await app.listen(3000);` becomes `await app.listen(3001);`

##  Getting started with the frontend - refine.dev

feel free to check out the refine [tutorial](https://refine.dev/docs/tutorial/getting-started/antd/create-project/#launch-the-refine-cli-setup)

### Creating the project: 
```sh
yarn create refine-app@latest -- -o refine-mui frontend-app
```

after all is installed 
`cd frontend-app`
`yarn dev`

### Let's do some clean up!
In the `src/App.tsx` remove the `<GitHubBanner />` component and the `<Route index element={<WelcomePage />} />`

#### Remove the simple-rest `dataProvider`, this line from `src/App.tsx` 
```react
import dataProvider from "@refinedev/simple-rest";
```

#### Add the `refine-use-generated` dataProvider.
 In the terminal run 
```sh
yarn add refine-use-generated
```
add in `src/App.tsx` 
```ts
import dataProvider from "refine-use-generated";
```
and change the dataProvider initialization to this
```jsx
dataProvider(new GraphQLClient('http://localhost:3001/graphql'))
```
full snippet 

```jsx
<Refine notificationProvider={notificationProvider}
routerProvider={routerBindings}
dataProvider={dataProvider(new GraphQLClient('http://localhost:3001/graphql'))}
options={{
  syncWithLocation: true,
  warnWhenUnsavedChanges: true,

  }}
>
```
#### Add the first resource 
1.  Add the `resources` prop in the `<Refine />` component

```tsx
<Refine notificationProvider={notificationProvider}
              routerProvider={routerBindings}
              dataProvider={dataProvider(new GraphQLClient('http://localhost:3001/graphql'))}
              options={{
                syncWithLocation: true,
                warnWhenUnsavedChanges: true,

              }}
              resources={[
                {
                  name: "blog-posts",
                  list: "/blog-posts",
                  show: "/blog-posts/show/:id",
                  create: "/blog-posts/create",
                  edit: "/blog-posts/edit/:id",
                },
              ]}
            >
```

Take a closer look at the section:

```ts
 resources={[
                {
                  name: "blog-posts",
                  list: "/blog-posts",
                  show: "/blog-posts/show/:id",
                  create: "/blog-posts/create",
                  edit: "/blog-posts/edit/:id",
                },
              ]}
```

The name of the resource is in plural and kebab-case, the rest are routes for corresponding operation.

2. Add the routes and
components.

```tsx
<Routes>
  <Route path="blog-posts">
    <Route index
      element={
        <MuiInferencer
          meta={{
            'blog-posts': {
              getList: {
                fields: ["id", "title", "content"],
              },
            },
          }}
        />}
    />
    <Route
      path="show/:id"
      element={
        <MuiInferencer
          meta={{
            'blog-posts': {
              getOne: {
                fields: ["id", "title", "content"],
              },
            },
          }}
        />}
    />
  </Route>
</Routes>
```
also add the `MuiInferencer` import like so 
```ts
import { MuiInferencer } from "@refinedev/inferencer/mui";
```
Go to http://localhost:3000/blog-posts and see you newly created page

What happen here ? what is the  MuiInferencer ?

Inferencers from Refine are components that have the CRUD functionality, it needs a basic configuration in the meta prop like this 
```
[resource-name-plural]:{[operationName]:{fileds:["field1","field2","field3"]
``` 
Note the `operationName` for the list is `getList` and for show is `getOne`.
the path of the route should match the ones defined in `<Refine />` component property `resources`

### Generated code by MuiInferencer
If you go to http://localhost:3000/blog-post  you will notice a black banner with a blue button `show the auto-generated code` press on that and you get the code of component which can replace the `MuiInferencer`.

your code should look like [this](https://github.com/usegen/refine-use-generated-demo-1/tree/6d449b33eaba61c891468488b705d622a28336ae)

to be continued ...