Fullstack CRUD application with Fastify, Mongoose and React Admin (Part 2— Frontend)

Image for post
Image for post

Hey guys, this is the second part of my tutorial about Fastify and React Admin. In this second part we are going to build the frontend of our CRUD todo list application with React admin and connect it to the Fastify backend we developend previously! If you missed part 1, you can find it here. If you want to skip reading and go straight to the code, you can find all the frontend source code here, and the complete backend code here!

Small Recap

So as a small recap for the previous part of the tutorial: we put together a Fastify app, connected it to our MongoDB and created a collection of notes. We also created a Note Model to be able to perform classical CRUD operations on our collection and set up the endpoints following REST conventions. Finally, we added a preHandler Hook that manipulates our responses, adding a Content-Range header that contains the name of our resource (notes), information about the pagination and the total number of notes in our database, as required by React Admin documentation. We will not have to worry about thiese headers on the frontend side since React admin is going to take care of them automatically. We are now ready to setup the frontend project so…

Image for post
Image for post

Project Setup

Choose a location on your pc and open your terminal. This time aroud we don’t need to create a folder for the project since create-react-app will create it for us. Type the following in your terminal:

npx create-react-app notes-client
cd notes-client
npm install react-admin @material-ui/core --save

In doing so, we created a new folder called notes-client for our project and installed both React admin and Material-UI. This allows us to leave the styling/CSS part of the application aside from our concern, since React admin basic component have a basic styling based on the Material-UI library.

Before you go on, open your terminal and make sure everything compiles correctly by running npm start. If so, you should see your browser popping up with the classic React App logo spinning into your main page at localhost:3000.

A little cleanup

Using create-react-app is very handy when we want to rapidly initialize a React app, but brings with it some files which are useless for this project. Inside the src folder of the project, you can get rid of the following files: App.css, App.test.js, logo.svg and setupTests.js.

Also, we will clean the App.js file so that our final result will be the following:

The Data Provider

Before we actually start to use React admin and its component we have a very important step ahead. In order for React admin to perform its magic, we need to specify a dataProvider to be used whenever it needs to communicate with the APIs.

The dataProvider is but an object that must have the following methods:

const dataProvider = {
getList: (resource, params) => Promise,
getOne: (resource, params) => Promise,
getMany: (resource, params) => Promise,
getManyReference: (resource, params) => Promise,
create: (resource, params) => Promise,
update: (resource, params) => Promise,
updateMany: (resource, params) => Promise,
delete: (resource, params) => Promise,
deleteMany: (resource, params) => Promise,
}

Quoting directly from the official documentation:

the Data Provider’s job to turn these method calls into HTTP requests, and transform the HTTP responses to the data format expected by react-admin. In technical terms, a Data Provider is an adapter for an API.

If you are lucky enough, you can find a ready-to-use dataProvider for your backend framework among the officially Available Data Providers. In that case you can just import the data provider in your project and pass it to the Admin component that will wrap the entire application (see later).

In our case, we wll have to face a small issue: React admin expects an id property as a key for the resources we want to manipulate, but on MongoDB, the key for documents is _id . Therefore, as explained in the FAQs section of the docs, we will have to define our own provider and remap the id property to our _id key.

Scrolling down the dataProvider documentation page, we can find a full example of dataProvider implementation, which needs just a few updates on our side in order to work fine with our database.

So this is what we will do: we will copy the entire implementation example, and just remap the keys of all methods we need to use in this fashion:

return { ...json, id: json._id };

Here is the final result:

Important Note: at the top of the file, we defined the apiUrl to localhost:3000/api even though our backend app is running on port 5000. This is to prevent CORS problems and needs an extra step: inside your frontend package.js you need to add a “proxy” property as follows:

"proxy": "http://localhost:5000"

The Admin Component

Okay my friends, with the dataProvider in place we are finally ready to get our feet wet with React admin components, so let’s begin.

As a first step, what we need to do is wrapping ouur whole application inside the Admin component. The Admin component represents the whole backoffice of our application and it has just one mandatory prop: dataProvider. Let’s open again our App.js file:

We imported our dataProvider and passed it as a prop to the Admin component. However, Admin alone cannot do much without some resource to work with…

The Resource Components

The Resource components are the core of React admin. Each of them represents a single resource model inside our backoffice, and will take care of showing the appropriate component for each of the operation we want to perform on the resources they stand for. We could pass as many Resource components as we want as children of Admin, but in our case, we only have our resource to work with: our notes. Let’s edit App.js one more time.

We imported the Resource component and pass it 3 important props:

  • name defines the name of the resource that will displayed in many places throughout our frontend backoffice panel
  • list specifies a component to show when we need the list of the resource, usually a table.
  • edit specifies the component to show when we edit a resource, that is, a form.
  • create: specifies the component to use when we create a new resource, in other words, a creation form.

In the file above, we are importing and assigning a few component files that do not exist yet, so let’s create them now and we will work on them one by one right after! Inside your project root folder open the terminal, create a component folder and the three files: NotesList.js, NotesEdit.js, NotesCreate.js

mkdir src/components
touch src/components/NotesList.js
touch src/components/NotesEdit.js
touch src/components/NotesCreate.js

Displaying the list of notes

To display the list of all our notes, we need to work on the component passed to the list prop of our Resource: NotesList.js:

Lot of stuff here, but really easy after all! As a first step, we imported a bunch of components from React Admin. All of them feature pre-built functionalities that will build our table for the list in a blink of an eye.

First things first: the List component is what we use when we want to set up a list page. We spread the props with the information coming from the Resource and Admin parent components, that will make List aware of which resource we are listing and which methods to use when contacting the APIs.

The Datagrid component is the acual table in which we can specify the columns we want to show. Each children of Datagrid will be displayed as a column. We provided 2 TextField components; one to display the id column and another for the text column. Note that the source prop of these components must match the proprties of the resource, that is, the properties we defined inside our NoteSchema, with the exception of the _id which has been mapped in the data provider as id .

After that, we also provided the EditButton and the DeleteButton so to have the relative actions on each row. What is important to note is the basePath prop inside the button components: here is where the magic of React Admin reveals itself. The path we specify will be joined to the baseUri defined inside the dataProvider, and React Admin will automatically add the id of the instance we want to delete or edit, as expected in the REST conventions!

While the DeleteButton will now work out of the box, we need a further step for the EditButton: define the NotesEdit component to show when the button is clicked.

Edit a note

The EditButton defined in the NotesList component will redirect the view to the component that we provided in the edit prop of the Resource component: NotesEdit.js. Let’s put inside the following code:

This time around, we want to create a page to edit a resource so the Edit component is what suits us. We pass inside it the spread props, and then we pass a SimpleForm component as its child, since we definetly need a form to edit a note!

Inside SimpleForm we can list a number of components to render the different fields we want to show. Again, the source prop of these components must match the resource proprties so we have one TextInput component for the id and one for the actual text of the note. We also marked the id field as disabled since we don’t want to let users to edit the id of our notes; and the text field as required because a note without text… well, is not a note.

Image for post
Image for post
Final look of the edit form

Creating a new note

Our last step is to define the NotesCreate.js file that is supposed to show a component to handle the creation of new Notes.

By clicking on the plus icon at the top of the Notes view, this component will be rendered. Let’s instruct React admin on what to show within it:

This is definitely the easiest component and it is very similar to the NotesEdit. The only differences are the use of the Create component instead of the Edit one, and the obvious absence of the id field, since the id will be automatically assigned to the new notes by our MongoDB.

Image for post
Image for post
Final look of the Creation Form

TA-DAH!

Image for post
Image for post
Final result, note the create button and the CSV export on the top right side, the left side of the app is where all our resources will be listed

There we go my friends! 5 files in total (included the copy-pasted data provider), and this is what we get, perfectly working and already styled. Would you believe it was so easy? And, you also got CSV Download out of the box!

I’ll leave the next steps to you so to play around with this application: I invite you to complete the app for multiple actions such as multiple cancellation (hint: you need to edit the dataProvider.js file), try to add filters, sorting rules , restyle the appearence and if you want, try to add other resources!

I really hope you enjoyed this tutorial and hope you also got in touch with some tech you didn’t know. See you in the next tutorial!

Written by

Passionate Coder. Currently Front End Developer @ CWS Digital Solutions

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store