Fullstack CRUD application using Fastify, React, Redux & MongoDB Part-1
Let’s create something interesting
Hi, there. I hope that you are having a good time. Now let’s make it even better. In today’s tutorial we’ll be building a Fullstack Application using Fastify, React, Redux and MongoDB, which would support all CRUD functionalities. The application that we are about to build is a simple menu app that lists all the menu items currently present in the database, In this application, you would be able to create menu items, which could hold details like item-name and item-price. You could also modify them or even delete them. If you want to see all these features live in action, feel free to check out it’s completed version live here and play with it, till you are able to get a high-level grasp of what you’ll be building throughout the rest of this tutorial. The final source code of the application is available here. This tutorial would be a two-part series, In its first installment we would be building a static implementation of Web App using React and Redux, And in our second installment we’ll be wrapping up with app by adding a Fastify.js backend and MongoDB database.
Seeing the popularity of React, Redux, Fastify, and MongoDB. It would be pretty interesting to find out how they all aces work in conjunction. So lets without wasting any time dive right in!
Things to know before getting started
This tutorial is for anyone who is interested in learning new things and has some basic knowledge of React, Redux, MongoDB, and RestAPIs in general. React developers who haven’t coded for a while yet, can also follow along in order to get back in their old form. Though I would be giving my best to explain each piece of code as we build the app. But it would be of great help if you have you have some basic understanding of core concepts already. In addition, we’ll be using quite some ES6 syntax, so it would be pretty good if you know some of them already like arrow functions and spread operator.
So, Enough of talking, let’s get started!
Project Setup
Before moving on please ensure that you have node.js installed in your machine, If not then please get it installed before heading forward. You can install node.js from its official site https://nodejs.org
After getting node.js installed, Now let’s start by initializing our project by executing commands shown below in your terminal.
mkdir fastify-react-crud
cd fastify-react-crud
touch .babelrc
mkdir server
mkdir src && cd src
touch index.html index.js menu.js menu.css
mkdir components && cd components
touch form.js menuItem.js
cd ..
mkdir redux/actions
mkdir redux/reducers
mkdir redux/store
cd redux/actions && touch actions.js && cd ../../
cd redux/reducers && touch reducer.js && cd ../../
cd redux/store && touch store.js cd ../../../../
Alright!, So that was a lot of setup code. But we were going to do it anyway, so I preferred to keep them stacked together so that we have the least chances of getting differences in our file structure.
Note: In case you are on windows and are using windows Powershell, Please shift to git bash/cmd because concatenation of commands using &&
operator doesn’t go well with windows PowerShell.
Now let’s install some npm packages to get going. We’ll start by building our View Layer. So let’s install some packages required to build our React frontend.
Note: We’ll be using Parcel Bundler to develop our react frontend. In case you are unaware of the parcel, then you should know that in a nutshell, it’s nothing more than an application bundler similar to webpack. We’ll be using the parcel as it’s just comparatively easy to set up and work with.
Now if you had executed the shell commands right, you must already be in the project root. But in case for any reason you are not, please navigate to your project root and execute commands shown below.
npm init -y
npm i --save react react-dom redux react-redux redux-thunk uuid
npm i --save redux-devtools-extension
npm i --save-dev parcel-bundler
npm i --save-dev @babel/plugin-proposal-class-properties
open package.json
and add dev
script shown below
"scripts": {
"dev": "parcel src/index.html"
}
Now, open .babelrc
and copy-paste the line shown below. So that we can use arrow functions in our React components.
{
"plugins": [ "@babel/plugin-proposal-class-properties" ]
}
After having all the commands executed successfully, you must be having your project file structure quite similar to like this.
fastify-react-crud
|--node_modules // contains node modules
|--server // will contain server related files
|--src // will contain cleint side related files
|----components // will contain child components of menu.js
|------form.js // form component for Addition & Updation
|------menuItem.js // component to display menu item
|----redux // contains redux related files & folders
|------actions
|--------actions.js // contains redux actions
|------reducers
|--------reducer.js // contains redux reducer
|------store
|--------store.js // here we create redux store
|----menu.css // will contain css code
|----menu.js // will contain react code
|----index.html // will contain html template
|----index.js // will contain react code
|--package.json
|--.babelrc // babel plugin config
Let’s start building our React-Redux Frontend!
Quick Structure Analysis
If you have seen the demo already, then the image shown below might seem quite familiar to you. If you’ve not visited the demo link yet, I’ll highly recommend you to visit. Because it would give you a broader picture of the project that we are about to make.
Now after you have seen the demo, You can easily interpret by seeing the above image, that our App consists of <Menu/>
component, which wraps major functionality of our application. Later as we start coding you’ll get to know that it’s also kinda powerhouse of our application because this is the only component in our application that would be communicating with the redux store. As we go one layer deep <MenuItem/>
component comes to our notice, It displays the data in really nice formatted fashion and besides that, it also provides us with the ability to Modify and delete data using their respective buttons. When you click on the Edit button or Create New Item Button, you would unlock another component which is <Form/>
component. It is a very important component because this single component is used in two different situations i.e. Addition of Items and Modification of items. It also has his own set of functional buttons using which we can either submit our data or cancel the request which can be either of addition or update. So, Now that you have understood what individual component actually does or at least what it’s supposed to do. I think we are ready to get our hands dirty with some code.
Let’s start by Redux first, So that later on when we build components we know what’s happening under the hood and how is it happening
Enter Redux!
Okay, Now In case you are confused about some basics of redux, like what does what or what is the relationship between them, then the image shown below might clear some mist around it.
Step 1: Lets start by defining some action, Open src/redux/actions/actions
and copy the code shown below.
Now in case you are wondering what action is ? then you should know that in a nutshell, it’s job is only to trigger some piece of code defined in reducer, which would, in turn, update the store depending on the type of action and that’s it, nothing more! You might have already observed a pattern from code above, that an action creator always returns an action object. The action object that’s to be sent by action creator essentially expects two properties namely type
and payload
. Of both type
is mandatory to be specified no matter what. for eg. readItem
action creator doesn’t require a payload but would not work without type
property. Now in case you are wondering what a payload
actually is? then Basically it’s just a piece of data that is sent from our view layer to reducer for a variety of purposes, for eg. Create, Update, Delete. Now coming back to our actions file, here we have
createItem
: It acceptsitem
to be created as it’s payload and it’s dispatched when we want to add a new itemupdateItem
: It also acceptsitem
to be updated as it’s payload and it’s dispatched when we need to update any item.deleteItem
: It acceptsid
of the element to be removed as it’s payload and it’s dispatched when we need to delete any item.readItems
: It is dispatched to read items from redux-store. It doesn’t have any payload yet. But in the next part of the tutorial, it would play an important role, as it would be used to fetch items from the database.
Now I think actions are all clear, let’s try to clear our next hurdle i.e. reducers
Step 2: Open src/redux/reducers/reducer.js
and copy code shown below.
So, that’s what our reducer looks like, like all ordinary reducers we have
- An initial state for store represented by
initialState
variable - we have reducer function which expects two arguments namely,
state
andaction
.
Whenever we dispatch an action creator it sends an action object to reducer (You should be nodding right now). That object has a mandatory property type
. And that’s mandatory because we require type
in order to identify an action distinctly from others, you can think of it as an id for the action. Depending on the type of action, Our reducer decides whether to Create items, Read items, Modify items or Delete items. But whatever it decides it has done it by not mutating the original state. Because in case you mutate state, the store’s state may get updated but react will not detect it and you would not be able to witness changes in your react app. FYI 90% of errors in any redux app happens due to a mutated state. So, always be careful to not accidentally mutate the state while working with the redux app.
In order to work with immutability, we need to create a copy of the original state. There are generally 2–3 ways to do it. I have used the latest and easiest of all, which is by using the spread operator. If it’s new to you, feel free to visit docs here. I can not discuss more about “immutability” right now, because it’s a topic which demands it’s own tutorial, so we’ll leave it here only. For now, you only need to know that [...array]
is a copy of and array
and {...object}
is a copy of an object
. Now, Let’s get back to our reducer.
- In our state, we have a
menuItems
property which is of type array. - On action type
CREATE
we add an item tomenuItems
array and send a new state back to our view. - In case of action type
READ
we simply return the stored state. - In case of
UPDATE
we map over the copy of themenuItems
and send the state after updating the content of the desired item. One important thing to notice here is that here we don’t need to make a copy ofmenuItems
it because when we use map to iterate of elements, a new copy of the array is automatically created and returned. But I have done it just for double safety (Ya that’s the fear of mutating the state xD). - Now in case of
DELETE
we simply return the filtered array by ignoring the item which has id similar to what was passed in the payload.
That’s It for our reducer. I hope, that you were able to understand the reducer. Let’s bind up with the redux section by creating store.
Step 3: Open src/redux/store/store.js
and copy the code shown below.
So, now that’s the shortest piece of code in the whole project. Well, it imports quite some things. Let’s discuss all in brief quickly. createStore
is used to create a redux store, applyMiddleware
is used to add middlewares (middleware provides a third-party extension point between dispatching an action, and the moment it reaches the reducer). Next up is thunk
. It allows us to write action creators that return a function instead of action (It would come handy when we will be fetching data from the server, but not now ;)). It also imports reducer which I don’t think requires any explanation. Now last import is composeWithDevTools
which we use in order to take advantage of redux dev tools along with custom middlewares. After importing we create a middlewares array and add thunk to it. Now as a final step we create a store using createStore
and export it. We’ll be importing it in index.js
later in this tutorial. So that’s all for the redux but to see the functionality we build, we require View Layer so let’s get this one done quickly using React!
Let’s create something presentable!
Step 1: let’s start with index.html, Open index.html and copy the code shown below.
This code above is all self-explanatory we just have a link tag for font awesome icons, which we use in buttons. It’s completely optional you can write texts in buttons instead if you desire. Besides the link, we have also a script tag to import index.js
.
Step 2: Now, navigate to src/index.js
and copy the code shown below.
This is the outermost wrapper component of our react app, It was skipped during structure discussion. Actually It doesn’t do much besides making the store available to our Menu component. Other than that rest must be self-explanatory. Now next up we’ll be building <Form/>
component, It would be going to be quite interesting at least as compared to the first two steps xD.
Step 3: Now, Open src/components/form.js
and copy the code shown below.
So that’s what our <Form/>
component looks like, If you read the code once, You would realize that it’s nothing more than an ordinary form having two input fields and two buttons that are used to submit and close the form. When we press submit button handleSubmit
function gets invoked and on pressing, cancel button handleCancel
function gets invoked. They both make further calls to respective functions in the parent component. For time being just forget about these parent component’s functions. Just remember that handleSubmit
sends the form data to the parent component and handleCancel
closes the form and that’s it. We’ll learn about these parent component’s functions in detail later, till the time you should just know that what they do.
All right now let’s talk about its state, you can see that we are not taking it empty by default rather we check for props and initialize state with values passed in props in case they were. That’s because our <Form/>
component is a multipurpose component, It is used as Create Item Form as well as Edit Item Form, so when it’s used as Create Item Form no props are passed so the state remains empty and the user sees empty fields as they should. But when it’s used as Edit Item Form, props are passed and input fields get filled with values passed in props thus the user is able to see the value that he/she is about to edit.
Now next up is our handleChange
function, It basically changes the state of name and price whenever values in input fields are changed. It’s able to do so because it’s attached to both of the input field’s onChange
events and get’s triggered whenever the value in input is changed. Inside the function we use object destructuring to extract name
and price
from state. and change the relevant state property which is decided by the value of e.target.name
(It only works when input field has name attribute).So that was our <Form/>
component for you, next up we’ll write code for menuItem.js
Step 4: Now let’s build<MenuItem/>
. You may open src/components/menuItem
and copy the code shown below.
Now It may have a few more lines of code as compared to <Form/>
component discussed above a while ago. But it is quite simpler compared to it in terms of functionality. Similar to <Form/>
we also have a state which we initialize with the values passed by the parent component. But in this scenario, we opt for a different technique to do it rather than initializing directly in the constructor which is sometimes not recommended though. In <MenuItem/>
we use componentDidMount
lifecycle method to update the state with the props whenever component mounts. Apart from name
, price
we also have openEditForm
property in our state which is component-specific and it has nothing to do with its parent component. openEditForm
is basically used to toggle Edit Item Form. It doesn’t have any more applications. Similar to <Form/>
It also has a pair of buttons, but their functionality is quite different. Two Buttons are Edit and Delete. When Edit button is pressed handleEditClick
function is invoked which sets openEditForm
to true
which in turn opens the form to edit items and whereas when the Delete button is pressed handleDelete
is invoked. In addition, there is also handleUpdate
function which gets invoked whenever a user submits after editing i.e. sends update request. Both handleDelete
& handleUpdate
make further calls to functions defined in <Menu/>
component in order to actually delete and update the item from storage. We will look at these functions in menu.js
next up in great detail. So that’ all for <MenuItem/>
, let’s see up next what <Menu/>
has us to offer.
Note: when handleUpadte
is invoked it also sets openEditForm
back to false
which toggles form and lets us see the saved content of that item.
Step 5: Now let’s open src/menu.js
and copy the code shown below.
Alright Now that’s quite a lot of code compared to the first 2 entries. But that’s just because it handles a lot of functionality. All our create, update, deletion in the store are initiated from this component only. I have commented on every useful block of code and I am confident that if you go through it once on your own, you would get a good percentage of code in your first attempt only. Because it’s just lengthy otherwise it’s easy to understand. So give it a try, go through whole code once and return here, I promise it would prove beneficial and you would thank me after this.
Alright, So how did it go? I am positive that you would have been able to get at least some piece of code if not all. Well, that’s Okay. Also, you should be proud of yourself even if you got even some piece of it because it’s never easy to read someone else’s code xD. Alright so now let’s get serious and get the job done. Now I’ll be going through the above code, follow along and Let’s check how much of it you got right! Well, by merely seeing the imports one can recognize that this component communicates with the redux store, uses <MenuItem/>
and <Form/>
components (we’ve discussed them above already), imports css and we also import some action creators that we created in action.js a while back.
Now let’s talk about its internal state. Well, It’s internal state doesn’t have much to offer except an openAddForm
property whose job, in a nutshell, is just to toggle the display of creating item form, well that’s expected behavior when your app uses redux as then our major state resides in our redux store. Next, we have a fair amount of handlers here, Remember when I said that Menu.js is the powerhouse of our application. You can say that these handlers our the ones which provides it with power.
- First handler to encounter is
handleAddClick
, Now it’s very similar tohandleEditClick
discussed while creating<MenuItem/>
component. It’s also used to setopenAddForm
totrue
which in turn toggles the Add Form Component. - Now next up is
handleAddItem
function which is used to add item to redux store. It receives data when the Add Form (same<Form/>
component used inMenuItem
, but rendered with empty fields) is submitted. It checks for falsy values and in case it founds one it replaces them with default value. After verification of valuescreateItem
action creator is invoked with new item as argument and rest is all taken care by redux. - Now next event handler is
handleDeleteItem
which is used to remove item from redux store. It is invoked by<MenuItem/>
with id of item to be deleted. In turnhandleDeleteItem
in turn invokesdeleteItem
action creator with id of item to be deleted as argument. - Next event handler that we come across is
handleUpdateItem
which is used to update item in redux store. Like in previous handler, It’s also invoked by<MenuItem/>
but with full item object not just id. in turnhandleUpdateItem
dispatchesupdateItem
action creator with item object as argument. - Now last event handler to encounter is
handleCancel
which is quite similar to one defined in<MenuItem/>
, so you already know what it does.
Majority of the code is commented so the rest of the code may not require any additional explanation. Other than that we have defined mapStateToProps
function in order to subscribe to redux store state updates. Here we subscribed for updates for menuItems
property. As a last step we connect our <Menu/>
component to redux store using connect
, After connecting to store we get menuItems
as prop to <Menu/>
component. So that’ all folks for the menu.js
. Now we just need to run it and see what we built so far.
Hey don’t you think, we are forgetting something? Yes, we are. Our menu.css
is still empty. And if you run your app now, It could well be a nightmare. If you want you can use the css that I wrote for this app and not waste time on writing your own. You can download css from here.
Now navigate to a terminal and execute npm run dev
and navigate to http://localhost:1234/ and you might be seeing the application up and running very similar to shown below.
What’s next?
Alright, folks! We’re done with our first leg of the two-part tutorial. Till now we’ve successfully created a fully functional React Redux CRUD application. But it still has one problem that needs to be fixed, which is that the changes are not persistent and it disappears whenever the app is reloaded. So, In the next part we’ll be making changes persistent, for which we’ll be using fastify and MongoDB Atlas. It would be quite interesting to see how these all techs work in conjunction. So let’s meet in its second part where we’ll add Fastify and MongoDB Atlas to our current application.
If you enjoyed this post, I’d be very grateful if you’d help it spread by sharing it with a friend, via Twitter or Facebook. And as always please let me know in comments how did you find this tutorial. Thank you!.
Wanna read more? You may like this as well -