usegen
Posted on June 13, 2023
What is 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 ?
A CLI that auto-generates a CRUD NestJS, Prisma ORM, GraphQL API in minutes.
- Define the database models in Prisma ORM.
- Describe your API, query depth, authorization/ authentication in a simple configuration file.
- Run a CLI command. Congrats! you have a GraphQL CRUD API, as nested as you want, with filter and sort for nested queries.
- **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 and use the code EGDCONX to get it free (limited offer). Download and extract the content.
Getting started with the backend - Initial setup
- Create a NestJs App
npm i -g @nestjs/cli
nest new project-name
replace the package.json with the one received with this module
Add the use-generated folder at the same level as the NestJs app and run yarn or npm install
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
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
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
...
"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
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
Creating the project:
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
import dataProvider from "@refinedev/simple-rest";
Add the refine-use-generated
dataProvider.
In the terminal run
yarn add refine-use-generated
add in src/App.tsx
import dataProvider from "refine-use-generated";
and change the dataProvider initialization to this
dataProvider(new GraphQLClient('http://localhost:3001/graphql'))
full snippet
<Refine notificationProvider={notificationProvider}
routerProvider={routerBindings}
dataProvider={dataProvider(new GraphQLClient('http://localhost:3001/graphql'))}
options={{
syncWithLocation: true,
warnWhenUnsavedChanges: true,
}}
>
Add the first resource
- Add the
resources
prop in the<Refine />
component
<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:
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.
- Add the routes and components.
<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
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
to be continued ...
Posted on June 13, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.