Creating a fullstack REST backend with node.js, Express and MongoDB (mongoose) and creating React frontends using React Data Grid and Material-UI DataGrid to access the service
Many programmers are aware that backends are commonly built using technology stacks like Java and SpringBoot, Python/Django, PHP/Laravel and RubyOnRails but you can also use node.js as a REST backend thus reducing the width of the technology stack and reducing the requirement on the number of programmers who specialize in different backend languages. Using node.js also allows you to use the latest Javascript and leverage on the latest technologies.
In this article, I will show you how to create a node.js REST API backend with full CRUD functionalities using MongoDB on a Windows 10 machine with Visual Code. We are going to use mongoose.js to simplify working with MongoDB from node.js.
Please note there is an extension of this article titled, Deploying a Node.js server-side backend CRUD REST service to Heroku connected to a cloud-based MongoDB Atlas database where I show you how to deploy this node.js app created to Heroku cloud hosting and also to use the cloud-based MongoDB Atlas for public deployment.
We will then try to access this backend with a node.js frontend using axios and adazzle’s React-Data-Grid component and then try it with the Material-UI/DataGrid.
(Note on my earlier articles — For a rundown on fullstack Java and REST backend development and React frontend development, please check out : Creating a fullstack React/Material-UI DataGrid frontend data grid connected to a Java SpringBoot REST GET API backend with axios.
This article is further extended with my other article, Creating a fullstack Java app with AJAX HTML frontend using jsGrid datagrid and Apex Charts chart component calculating monthly averages from uploaded Excel data files on a Spring Boot REST backend running Apache Tomcat.
For a Python-Django REST API stack implementing HTTP GET, check out my other article, Creating a Python Django REST Service backend with Postgres database.
An Android/Google Location API article, Creating a Realtime Handphones Locations Tracker For Android Devices with Google Location API and Google Maps).
What are the advantages of creating a node.js REST API compared to the traditional programming languages?
Node.js is a technology built on Chrome’s V8 JavaScript engine that was first released in 2009. It is able to simultaneously handle multiple requests and provide prompt responses and comes with APIs that support HTTP requests, file systems and other server-side features for which other frontend APIs have limited support. Node.js has the following advantages:
- An I/O non-blocking model. This allows for serving multiple simultaneous requests, ensuring easy scaling and prompt execution of client requests on high-load platforms.
- Node.js is both a front-end and backend technology and hence can be used as a full stack solution reducing developer headcount.
- Node.js leverages on the JavaScript programming language which is the current trend.
- The development process is greatly accelerated by code sharing between frontend and backend.
- Node.js is open-source and does not require costly licensing.
- Node.js has a large and active community base which you can tap from.
Install MongoDB
MongoDB offers both an Enterprise and Community version of its powerful distributed document database. The community version offers the flexible document model along with ad hoc queries, indexing, and real time aggregation to provide powerful ways to access and analyze your data. For this exercise, we will install the Community version. Go to the MongoDB community website and download and install MongoDB.
After completing the installation, go to the MongoDB bin folder and view the files stored there. You can see the mongod.exe file which starts the server and the mongo.exe client file which is the client running on your machine. Go to the Windows command prompt and type :
mongod.exe
This will start the MongoDB server. Now type :
mongo.exe
to start the client.
Install node.js
Install node.js here. After that, test that you have installed node.js correctly by typing: node -v from a new command prompt which should return the node.js version number:
Create your application folder
Now create a folder from which you will build your backend app and from within this folder, you can install all the dependencies needed to build the node.js backend such as Express.js. For this project, we will create the folder path : C:\node_backend as shown in the screenshot below.
Install Express.js
Make the node_backend folder the current directory. We’ll install Express.js within this folder. Express.js, or simply Express, is a back end web application framework for Node.js, released as free and open-source software under the MIT License. Designed for building web applications and APIs, it has been called the de facto standard server framework for Node.js and can save a lot of time and resources for backend node.js programming.
Install Express (in the node_backend folder) using node package manager as follows:
npm install express
Install mongoose.js
Install mongoose by typing at the command prompt from your apps folder :
npm install mongoose
Install body-parser package
The body-parser package allows you to access the JSON data from the body of POST requests. Install the body-parser package by typing at the command prompt from your apps folder:
npm install body-parser
Start Visual Code
Now go to the node_backend folder and type : “code .” to open Visual Code from this folder.
Lets have a look at the package.json file generated:
We will create an app.js file where we will connect to the MongoDB database with mongoose.js and then we will use the express.js post function to do an HTTP POST request to add a model object (based on the mongoose schema) data to our database.
The model we will use is a User object with the following properties: user name, type of user, user password, telephone number and email.
We will create the User object in a separate Javascript file called User.js
User.js:
const mongoose = require(‘mongoose’);const UserSchema = mongoose.Schema({userName : String,userPassword : String,userType : String,userTelNo : String,userEmail : String,dateSaved: {type: Date,default: Date.now}});module.exports = mongoose.model(‘User’, UserSchema);
Now that we have created our model, we can go back to app.js and instantiate it. We can now receive a POST request externally for this User model and save this request User object to database with the save() method:
App.js:
const express = require(‘express’);const mongoose = require(‘mongoose’);const bodyParser = require(‘body-parser’);const cors = require(‘cors’);const app = express();const User = require(‘./User’);app.use(cors());app.use(bodyParser.json());//Connect to Mongo DBmongoose.connect(‘mongodb://localhost:27017/myapp’, {useNewUrlParser: true}, () => {console.log(‘Connected to MongoDB…’ + ‘mongodb://localhost:27017/myapp’);});app.listen(3000);// POST : save User userapp.post(‘/saveuser’, async(req, res) => {const user = new User ({userName : req.body.userName,userType : req.body.userType,userPassword : req.body.userPassword,userTelNo : req.body.userTelNo,userEmail : req.body.userEmail});try {const savedUser = await user.save()res.json(savedUser);} catch(err) {console.log(“ERROR : “ + res.json({message : err}));}});// GET : show all usersapp.get(‘/users’, async(req, res) => {try {const findAll = await User.find();res.json(findAll);} catch(err) {console.log(“ERROR : “ + res.json({message : err}));}});// GET : find by IDapp.get(‘/users/:userId’, async(req, res) => {try {const findById = await User.findById(req.params.userId);res.json(findById);} catch(err) {console.log(“ERROR : “ + res.json({message : err}));}});// GET : find by IDapp.get(‘/users/:userId’, async(req, res) => {try {const findById = await User.findById(req.params.userId);res.json(findById);} catch(err) {console.log(“ERROR : “ + res.json({message : err}));}});// UPDATE : update by IDapp.patch(‘/users/:userId’, async(req, res) => {try {const updateById = await User.updateOne({ _id: req.params.userId } , { $set : { userName : req.body.userName} } );res.json(updateById);} catch(err) {console.log(“ERROR : “ + res.json({message : err}));}});// DELETE : delete by IDapp.delete(‘/users/:userId’, async(req, res) => {try {const deleteById = await User.remove( { _id: req.params.userId } );res.json(deleteById);} catch(err) {console.log(“ERROR : “ + res.json({message : err}));}});
We can use Postman (or CURL) to send a test POST request without having to open an actual browser (see below). Make sure you set the Body settings to raw data and JSON format.
Go to the blank text area field within the Body tab and type out your raw JSON sample User data in Postman, as follows:
{“userName” : “Some user name”,“userType” : “Developer”,“userPassword” : “1234”,“userTelNo” : “603–251–4299”,“userEmail” : “ me@abc.com”}
Now in Postman, check that you are sending a POST request in the grey header panel above the Body area (change it from the GET default). Finally, click the Send button to submit the POST request.
You should be able to get the response JSON string return prompt (like below) of the User object that you sent, together with the auto-generated Id :
{“_id”:”603fe488bf58b32b4813e06b”,”userName”:”Some user name”,”userType”:”Developer”,”userPassword”:”1234",”userTelNo”:”603–251–4299",”userEmail”:” me@abc.com”,”__v”:0}
Explanation :
The following line :
mongoose.connect(‘mongodb://localhost:27017/myapp’);
connects your app to the MongoDB database and creates a database called myapp. You may have more than one databases in your MongoDB database. To show all databases, simply type: show dbs from the MongoDB client command prompt window (opened when you typed mongo.exe as explained earlier).
Since your database is called myapp as aboye, you want to make it the current database by typing : use myapp from the MongoDB client command prompt window (opened when you typed mongo.exe as explained earlier).
Now type : show collections, to view all the collections available within the current database in use, which is myapp.
You should now be able to see the users collection listed, which is from the User model schema which you setup in your application within Visual Code, using the mongoose.schema. Now type: db.users.find() to view all the items in your users collection :
The default port 3000 of node.js is used here so the following command listens to request through this port:
app.listen(3000);
Save A New User (POST)
The line :
app.post(‘/saveuser’, (req, res) …
from within App.js instantiates an instance of the User model called user and then receives the POST request from the browser (Postman) and processes it and saves it to the database with the line :
user.save()
Update An Existing User (PATCH)
The line :
app.patch(‘/users/:userId’, async(req, res)…
from within App.js receives a PATCH request (used to update data) from the browser (or Postman) and processes it and updates the record based on the userId submitted to be updated with this line :
const updateById = await User.updateOne({ _id: req.params.userId } , { $set : { userName : req.body.userName} } );
Note that the update() method has been deprecated and that updateOne() is the new method to be used for updating records taking in as inputs the record primary key, userId, in this case, and the the object model property to be updated from the request body. The rest of the CRUD functions are self explanatory.
(Note : you probably will encounter a CORS error if you are making requests from a different domain which is why we have the following inserted lines in the application :
const cors = require(‘cors’);
.
.
app.use(cors());
You will have to download the cors package first with npm :
npm install cors
This will fix the cross origin errors.)
The Front End
Alright, now that we got our node.js backend working, lets create a node.js frontend to access it using two Javascript datagrid components — adazzle’s React-Data-Grid and Material-UI/DataGrid. Please note that as at the date of this article, grid editing features have not been added to the Material-UI/DataGrid yet so it is a view-only grid but the React-Data-Grid is a fully editable grid.
React Data Grid
You need to add your React Data Grid component from adazzle’s GitHub page with npm or yarn into your project. Please note that there are two (2) packages for this grid component — one is for the basic grid with standard features (react-data-grid) but there is another supplementary component you have to install separately for the grid add-ons (react-data-grid-addons) which allows you to do row groupings and other additional features.
Add the React Data Grid through npm (or yarn):
npm install react-data-grid
After successful installation, check that it now appears in your package.json file:
Add code to access the REST service. There are a multitude of ways you can do this including using the many components available such as fetch(), superuser component, admin-on-rest, axios. In this article, we will use axios. Here is the frontend code to access the above backend service we have created earlier with axios and React Data Grid:
App.js:
import React, {useState, useEffect} from “react”;import ReactDataGrid from ‘react-data-grid’; // React Data Gridimport ReactDOM from ‘react-dom’;export default function App() {const [isLoaded,setIsLoaded] = useState(false);const [rowData,setRowData] = useState([]);useEffect(() => {const axios = require(‘axios’).default;axios.get(‘http://localhost:3000/users') // node.js MongoDB mongoose users REST service.then((response) => {setIsLoaded(true);console.log(response.data);setRowData(response.data);response.data.forEach(user => {});});}, []);// REACT DATA GRIDconst columns = [{ key: “_id”, name: “_id”, width: 250 },{ key: “id”, name: “ID”, width: 100 },{ key: “userName”, name: “User Name”, width: 250, editable: true },{ key: “userTelNo”, name: “Tel No”, width: 250, editable: true },{ key: “userEmail”, name: “EMail”, width: 250, editable: true },{ key: “userRole”, name: “Role”, width: 150, editable: true },{ key: “dateSaved”, name: “Date Saved”, width: 250 },];return(<div style={{ height: 700, width: ‘100%’ }}><div style={{ display: ‘flex’, height: ‘100%’ }}><div style={{ flexGrow: 1 }}><ReactDataGridcolumns={columns}rows={rowData}getRowId ={(row) => row._id}/></div></div></div>);}
You should be able to see the React Data Grid displaying the users data from MongoDB on screen when you type : npm start:
Material-UI/DataGrid
(Please note that as at the date of this article, grid editing features have not been added to the Material-UI/DataGrid yet so it is a view-only grid)
Add the Material-UI/DataGrid to your project with:
// with npm
npm install @material-ui/data-grid
// with yarn
yarn add @material-ui/data-grid
The grid requires the Material-UI core components and it must also be installed:
// with npm
npm install @material-ui/core
// with yarn
yarn add @material-ui/core
Here is how the App.js file looks like when we use the Material-UI/DataGrid:
import React, {useState, useEffect} from “react”;import { DataGrid } from ‘@material-ui/data-grid’;import ReactDOM from ‘react-dom’;export default function App() {const [isLoaded,setIsLoaded] = useState(false);const [rowData,setRowData] = useState([]);useEffect(() => {const axios = require(‘axios’).default;axios.get(‘http://localhost:3000/users') // node.js MongoDB mongoose users REST service.then((response) => {setIsLoaded(true);setRowData(response.data);response.data.forEach(user => {});});}, []);// MATERIAL DATAGRIDconst columns = [{ field: “_id”, headerName: “_id”, width: 250 },{ field: “id”, headerName: “ID”, width: 100 },{ field: “userName”, headerName: “User Name”, width: 250 },{ field: “userTelNo”, headerName: “Tel No”, width: 250 },{ field: “userEmail”, headerName: “EMail”, width: 250 },{ field: “userRole”, headerName: “Role”, width: 150 },{ field: “dateSaved”, headerName: “Date Saved”, width: 250 },];return(<div style={{ height: 700, width: ‘100%’ }}><div style={{ display: ‘flex’, height: ‘100%’ }}><div style={{ flexGrow: 1 }}><DataGridcolumns={columns}rows={rowData}getRowId ={(row) => row._id}id=”_id”/></div></div></div>);}
You should be able to see the Material-UI/DataGrid (see below) displaying the users data from MongoDB on screen when you type : npm start.
Differences between React Data Grid and Material-UI/DataGrid
Note that the main difference between both grids lies in the way each grid defines the column data. The Material-UI/DataGrid uses field and headerName to define each column whereas the React-Data-Grid uses key and name.