Build restful api using node.js, express and mongodb
Published By Suraj Sharma on 28-3-2021
In this post, we are going to perform CRUD(Create, Read, Update and Delete) operations in Node, Express, and MongoDB and we will also follow Model View Controller (MVC) pattern.
Requirements
- Download and Install Node Js.
- Download and Install MongoDB.
- Download and Install PostMan.
- You should have Some basic knowledge about Javascript and ES6.
- Curiosity and Interest ;)
Server Setup
We will initialize our project npm init
.
then we will add our dependencies express js and mongoose.
- Express: It is the framework for the Node.js web application. It provides routing, templating, Middleware, etc.
- Mongoose: It is an Object Data Modeling (ODM) library for MongoDB and Node.js. As we know that MongoDB is NoSQL. It is very flexible and we don't need to provide schema or structure. So mongoose helps us to provide MongoDB validations, Type Casting, Query Building, Hooks, etc.
To install the dependency in node, write
npm i --save express
and npm i --save mongoose
in terminal.
{SS of dependency installation and package.json}
Now require the express then initialize the variable app
and call express.
After that initialize another variable called PORT_NUMBER
and assign value 9000
.
Our Server will listen to this number. To listen we will call app.listen()
function then pass PORT_NUMBER
as an argument, pass a callback function. where console Server is running on 9000
.
const express = require("express")
const app = express()
const PORT_NUMBER = 9000
app.listen(PORT_NUMBER, () => {
console.log(`Server is running on ${PORT_NUMBER}`)
})
Let's make an API.
app.get("/api", (req, res) => {
return res.send("<h1> Hello World! </h1>")
})
In the above code we have called a functionget() then passed the path of the API and a callback function which has two arguments:req
,res
.
Express sends us two objects in this callback, which we called req and res, they represent the Request and the Response objects.
Request is the HTTP request. It gives us all the request information, including the request parameters, the headers, the body of the request, and more. The request object is enhanced version of the Node's own request object. This object has various properties like body, param, query, param etc.
Response is the HTTP response object that we’ll send to the client.
Let's create a small project where we will perform CRUD operations. Our Project Structure:
Middleware
Express has the middleware concept where middleware is the function that has access to the request, response object, and next middleware function in the application’s request-response cycle.
// app.js
// Express Middleware (Body Parser)
app.use(express.json())
// Our Middleware function to log some request's properties.
app.use((req, res, next) => {
console.log("Method =======>>", req.method)
console.log("Url =======>>", req.url)
console.log("Body =======>>", req.body)
console.log("Query =======>>", req.query)
console.log("Params =======>>", req.params)
next()
})
express.json()
is the function that parses incoming request bodies in a middleware before your handlers, available under the req.body
property.
Mongoose
Let's connect to our local MongoDB.
// app.js
const mongoose = require("mongoose")
// DB Connection
mongoose.connect(
"mongodb://localhost:27017/codeparadox",
{ useNewUrlParser: true, useUnifiedTopology: true },
error => {
if (error) {
console.log(error.message)
throw error
}
console.log("MongoDB Connected Successfully.")
}
)
// To log all queries that mongoose execute.
mongoose.set("debug", true)
MVC
Model View Controller (MVC) is a design pattern that divides application logic into three components which are interconnected.
- Model
- View
- Controller
Let's create a schema for the post-collection.
Model
The Model Component is responsible for data-related logic.
// PostModel.js
const mongoose = require("mongoose")
const postSchema = mongoose.Schema(
{
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
author: {
type: String,
required: true,
},
created: {
type: Number,
default: Date.now(),
},
},
{
versionKey: false,
timestamps: true,
}
)
module.exports = mongoose.model("posts", postSchema)
In the above code, we have required mongoose to then call the schema function and pass our schema object. In schema we have to define keys and their data type, also they are required or not. we have also passed another argument which is also an object where mongoose we do not add version key in the record and we will add timestamps which will be createAt
and updateAt
key.
After that, we are calling the model function of the mongoose and where are passing a string as the name of our collection, which is post
and another argument postSchema
.
Now let's create a controller where we are going to perform our CRUD operations.
Controller
The Controller act as an interface between Model and View. It takes input from the view and interprets then informs the model to make a change according to the user's input.
// PostController.js
const PostModel = require("../Models/PostModel")
const postController = {
// Create Post
savePost: async (req, res) => {
await new PostModel(req.body).save()
return res.json({ message: "Post added successfully!" })
},
// Get Post By ID
getPostById: async (req, res) => {
// data validation
if (!req.params.id) {
return res.json({ error: "Id is required" })
}
const postBydId = await PostModel.findOne({ _id: req.params.id })
return res.json({ data: postBydId })
},
// Get all Posts
getPosts: async (req, res) => {
const allPosts = await PostModel.find({})
return res.json({ data: allPosts })
},
// Update Post
updatePost: async (req, res) => {
// data validation
if (!req.body._id) {
return res.json({ error: "Id is required" })
}
await PostModel.updateOne({ _id: req.body._id }, { $set: { ...req.body } })
return res.json({ message: "Post updated successfully!" })
},
// Delete Post
deletePost: async (req, res) => {
// data validation
if (!req.params.id) {
return res.json({ error: "Id is required" })
}
await PostModel.deleteOne({ _id: req.params.id })
return res.json({ message: "Post deleted successfully!" })
},
}
module.exports = postController
All the functions are pretty straightforward, we have pass req
and res
and tried to validate our request then we have performed the MongoDB operations with the help of mongoose.
If you have read our MongoDB post, we have just done the same operations. With little change that now we are using mongoose and using some of its function like for insert, we are using save function to save a record.
After that, we have returned our data/message in the JSON form using res.json()
.
Routes
Routes could act as a view where it collects data or input from the user.
// app.js
// POST APIs
const postRoutes = require("./Routes/PostRoute")
app.use("/api/post", postRoutes)
In the above code, we are importing routes, using middleware where we are passing /api/post
path which means any request starting with this path and with any method will execute the postRoutes
.
// PostRoute.js
const express = require("express")
const router = express.Router()
const postController = require("../Controllers/PostController")
router.get("/", postController.getPosts)
router.get("/:id", postController.getPostById)
router.post("/", postController.savePost)
router.put("/", postController.updatePost)
router.delete("/:id", postController.deletePost)
module.exports = router
As we can see in the above code we have called Router class to create modular and mountable route handlers. A Router instance is a complete middleware.
So we have various methods like get, post, put, delete , patch etc and passed the path of the api and controller method.
In the path :id
is the param so that we can get id from URL with the help of req.param
property.
Let's run and check our all APIs.
POST
GET
All Posts:
Post By Id:
PUT
DELETE
Conclusion
We have implemented REST API and Crud Functionality using Node.js, Express and Mongodb. I didn't use an optimized way. It was one of the ways to implement. You can also check my other post about Vanilla Node.js (without any framework). Thanks for reading. if you found any issues or you have any query please contact.