Skip to main content

How to make NodeJS MongoDB REST APIs for CRUD operations


We'll use NodeJS Express framework for developing the web-interaction part and Mongoose for saving data to MongoDB. We'll be saving just two details name, and email of a user. Since I'll be logging in users with their email id only which is validated by Facebook in Facebook Social Login.

Install NodeJS and make a folder where your application will run from. This folder is production NodeJS server equivalent on Windows PC.

Step 1: Having installed NodeJS now open Command Prompt Window in the folder.

Quick Shortcut > Open the folder and click and type 'CMD' or 'cmd' in address bar.

Step 2: Initialize the application with a package.json file.
Run following command in the command prompt window,
$ npm init

name: (userdb)
version:
description: enter description
entry point: server.js
test command:
git repository:
keywords:
author: Your Name
license: 

Check details and type 'yes' to proceed.

Now our package.json is initialized and can be found in our project folder.

Note that we defined the entry point of our application as server.js so we'll make a file with the name 'server.js' had we left that blank the default name would have been 'index.js'

Create new file next to package.json by the name 'server.js', leave it blank for now we'll come back to it later.

Step 3: Installing dependencies
Now we'll install support for Express, body-parser and Mongoose for application to use it.
Run folowing commands in CMD
$ npm install express body-parser mongoose --save

Using '--save' at the end saves all the dependencies in the package.json file.

Now if you'll take a look at our project folder you'll see another folder by the name 'node_modules'.

Now let us setup our web server by editing the 'server.js' we created in Step 2.

Step 3: Open 'server.js' and define the main entry point to our application.

server.js

const express = require('express');
const bodyParser = require('body-parser');

// constant app will represent our application
// since app is based on express
const app = express();

//parses requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: true}))

//parses requests of content-type -application/json
app.use(bodyParser.json())

//defining a route to our application
app.get('/', (req, res) => {
res.json({
"message": "Nothing here, try making some API request."
});
});

//listening to requests
app.listen(3000, () => {
console.log("Server running at port 3000!")
});

Here, Express is a web framework that we are using to build REST APIs and body-parser is a module that parses the requests and creates req.body object that we can use in out routes.

Then we define a route to our application that addresses get request to the naked url and responds with a message. We'll alter this message with more helpful data later.

Finally we listen on port 3000 for incoming connection requests.

Let's fire up out server by calling

$ node server.js

You may visit http://localhost:3000/ to check whether it is running or not.

Step 4: Now let us configure our database.
Let's create new folder 'config' in out apps root folder where we'll be keeping all our configuration information separate.
Inside the 'config' folder create a new file 'db.config.js' with following contents-

module.exports = {
url: 'mongodb://localhost:27017/db0'
}

Now to import this 'db.config.js' file in 'server.js' and use it with 'mongoose'

//database congiguration
const dbConfig = require('./config/db.config.js');
const mongoose = require('mongoose');

mongoose.Promise = global.Promise;

//connection to database
mongoose.connect(dbConfig.url, {
useNewUrlParser: true
}).then(() => {
console.log('Connected to database');
}).catch(err => {
console.log('database connection failed...');
process.exit();
});

Re-run the server to check if the database is being connected.

$ node server.js

To remove the deprecation warning
"(node:8076) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor."

Just add ', useUnifiedTopology: true' after 'useNewUrlParser: true' so our 'server.js' is now

server.js

const express = require('express');
const bodyParser = require('body-parser');

//database congiguration
const dbConfig = require('./config/db.config.js');
const mongoose = require('mongoose');

mongoose.Promise = global.Promise;

//connection to database
mongoose.connect(dbConfig.url, {
useNewUrlParser: true, useUnifiedTopology: true
}).then(() => {
console.log('Connected to database');
}).catch(err => {
console.log('database connection failed...');
process.exit();
});

// constant app will represent our application
// app is based on express
const app = express();

//parse requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: true}))

//parse requests of content-type -application/json
app.use(bodyParser.json())

//defining a route to our application
app.get('/', (req, res) => {
res.json({
"message": "Nothing here, try making some API request."
});
});

//listening to requests

app.listen(3000, () => {
console.log("Server running at port 3000!")
});

Re-run the server warning should be gone now.

Quick Tip: The MongoDB database we just created can be viewed using MongoDB Atlas Applcation and passing the address 'mongodb://localhost:27017/db0' which we defined in 'db.config.js' file.

Step 5: Now we have our NodeJS application running with database connected. To save data to our MongoDB we will define a structure that will be followed for the data. We call this model. You can define more that a single type of model.

Create a new folder in the root directory of our application as 'app' and another folder inside 'app' as 'models'. Inside 'models' create a file by the name 'user.model.js'
Now we define what our user's properties are. Inside 'user.model.js' enter content-

user.model.js

const mongoose = require('mongoose');

const UserSchema = mongoose.Schema({
name: String,
email: String
}, {
timestamps: true
});

module.exports = mongoose.model('User', UserSchema);


Since I'll be logging and registering users using their Facebook login I defined only two string fields 'name' and 'email' which can be easily requested from Facebook login.

Also adding 'timestamps: true' will add two field 'createdAt' and 'updatedAt' which can be useful in their own way if required.

Step 6: Now we will define various routes for the APIs.
Create a new folder inside 'app' by the name 'routes'. Inside this folder we'll create a file 'user.route.js' with the content-

user.route.js

module.exports = (app) => {
var controller = "../controllers/user.controller.js";
const users = require(controller);

//create a new user
app.post('/registeruser', users.create);

//get all users' information
app.get('/allusers', users.listAll);

//get single user with userId
app.get('/users/:userId', users.findOne);

//update a user with userId
app.put('/users/:userId', users.update);

//delete a User with userId
app.delete('/users/:userId', users.delete);

}

Note that we have defined a variable controller which points to an address of 'user.controller.js' file which we will define in next step.
Before that let's first include 'user.route.js' in our 'server.js' file.
Add the following lines of code before 'app.listen()' method inside 'server.js'

//require Users routes
require('./app/routes/user.route.js')(app);


Step 7: Now let's define our 'user.controller.js' that our 'user.route.js' depends on.
Create a new folder by the name 'controllers' inside 'app' folder. Inside this create a new file 'user.controller.js' with following contents.

user.controller.js

const User = require('../models/user.model.js');

//register a new user
exports.create = (req, res) => {

};

//get all users' data
exports.listAll = (req, res) => {

};

//find single user with userId
exports.findOne = (req, res) => {

};

//update a user's information base on userId
exports.update = (req, res) => {

};

//delete user with userId
exports.delete = (req, res) => {

};

Now we will implement these individual methods

For registering a new user

//register a new user
exports.create = (req, res) => {

//validate the request
if (!req.body.email) {
return res.status(400).send({
message: "User email id cannot be empty"
});
}

//register a user
const user = new User({
name: req.body.name || "not defined",
email: req.body.email
});

//save the user information in database
user.save().then(data => {
res.send(data);
}).catch(err => {
res.status(500).send({
message: err.message || "Something went wrong while registering new user.."
});
});
};


For getting all users' data

//get all users' data
exports.listAll = (req, res) => {
User.find().then(users => {
res.send(users);
}).catch(err => {
res.status(500).send({
message: err.message || "Something went wrong while getting all information"
});
});
};

For getting single user's information

//find single user with userId
exports.findOne = (req, res) => {
User.findById(req.params.userId).then(user => {
if (!user) {
return res.status(404).send({
message: "user not found with id " + req.params.userId
});
}
res.send(user);
}).catch(err => {
if (err.kind === 'ObjectId') {
return res.status(404).send({
message: "User not found with id " + req.params.userId
});
}
return res.status(500).send({
message: "Error getting user data with userId: " + req.params.userId
});
});

};

Updating a user's information

//update a user's information base on userId
exports.update = (req, res) => {
//validate request
if (!req.body.email) {
return res.status(400).send({
message: "Email ID cannot be left blank"
});
}
//find user by userId and update its name and email
User.findByIdAndUpdate(req.params.userId, {
name: req.body.name || "not defined",
email: req.body.email
}, {
new: true
}).then(user => {
if (!user) {
return res.status(404).send({
message: "User not found with userId " + req.params.userId
});
}
res.send(user);
}).catch(err => {
if (!user) {
return res.status(404).send({
message: "Error updating user with id " + req.params.userId
});
}
return res.status(500).send({
message: "Error updating user with id " + req.params.userId
});
});
};


Deleting a user based on userId

//delete user with userId
exports.delete = (req, res) => {
User.findByIdAndRemove(req.params.userId).then(user => {
if (!user) {
return res.status(404).send({
message: "User not found with id " + req.params.userId
});
}
res.send({
message: "User deleted successfully!"
}).catch(err => {
if (err.kind === 'ObjectId' || err.name === 'Not Found') {
return res.status(404).send({
message: "User not found with id " + req.params.userId
});
}
return res.status(500).send({
message: "Could not delete user with id " + req.params.userId
});
});
});


In order to test you API you can use Postman. Screenshot attached below for registering a new user.



http://localhost:3000/allusers will retrieve all the data from database.

In the next part I'll be making a login and registering pages and push the database and server to production.

You can find the whole project on GitHub
https://github.com/ixabhay/ludoDB
This also contains lots of content that is up there in the post including a way to register a user and check their information for login.
Hope it helps.

Comments

Popular posts from this blog

Unity Mobile Game Optimization Checklist

- On Image and Text components that aren’t interacted with you can uncheck “Raycast Target” on it, as it will remove them from any Raycast calculus. - Click on your textures in your “Project” window. Click on the “Advanced” arrow, and now check “Generate Mip Maps”, Unity especially recommends it for faster texture loading time and a lower rendering time. - Set the “Shadow Cascades” to “No Cascades” (Quality settings) - If you have dynamic UI elements like a Scroll Rect with a lot of elements to visualize, a good practice is to turn off the pixel perfect check box on the canvas that contains the list and disable the items that aren’t visible on the screen. - Set all non moving objects to "Static" - Above Unity3d 2017.2 you should turn off "autoSyncTransforms" on the Physics tab - Always use Crunch Compression Low on textures - Try to keep the “Collision Detection Mode” on “Discrete” if possible, as “Dynamic” demands more performance. - You can go to the TimeManager w...

How to make download file button in react js

To create a download file button in React.js, follow these steps: Import the necessary dependencies: javascript Copy code import React from 'react' ; import { saveAs } from 'file-saver' ; Create a function that handles the download action: javascript Copy code const handleDownload = ( ) => { // Create a new Blob object with the desired content const fileContent = 'This is the content of the file you want to download.' ; const blob = new Blob ([fileContent], { type : 'text/plain;charset=utf-8' }); // Use the saveAs function from the file-saver library to initiate the download saveAs (blob, 'download.txt' ); }; Create a button component and attach the handleDownload function to the button's onClick event: javascript Copy code const DownloadButton = ( ) => { return ( < button onClick = {handleDownload} > Download File </ button > ); }; Use the DownloadButton component wherever ...

How to Convert Unreal Engine 5.1 Blueprint Project to C++ Project

To begin, open your project in the Unreal Engine 5 or a newer version of the editor.  Next, access the New C++ Class Dialog by selecting Tools and then New C++ Class .  From there, create a new "None" class and press "Create Class."  You might receive a warning message regarding the game module compilation, but you can disregard it and choose "No."  After closing any pop-ups, warnings, or success notifications, exit the Editor.  Proceed to your project's folder, right-click on the .uproject file, and select "Generate Visual Studio project files."  Double-click your project's .sln file to open it in Visual Studio.  In Visual Studio's Solution Explorer, find and choose your project.  Select "Development Editor" in the build configuration drop-down menu.  Right-click on your project and select "Build" to compile it without any errors.  Afterward, set the build configuration drop-down menu to "Development" ...