Easy-Peasy CRUD Operations in Express & Mongoose

Easy-Peasy CRUD Operations in Express & Mongoose

Recently, I had to build a REST API for my MERN project. I was going through the official docs and blogs on how to do it. But all of them were old and not even updated. After tinkering a little with the code, I got an understanding of Express and Mongoose to do things in the right and easy way.

What is the Mongoose?

Official Definition: Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js. It manages relationships between data, provides schema validation, and is used to translate between objects in code and the representation of those objects in MongoDB.

Didn't get it? Don't worry!

I will explain the above definition through a real-life example: Think of a Mongoose as your mother who does the hard stuff for you. So, you do the basic needs effortlessly.

Performing the Create, Read, Update, and Delete, and of course, the Validations is hard. If you have to do it directly on the database, Then you have to write tons of boilerplate code to do such basic stuff.

As you know, MongoDB is a document-based database. And, Frequently, we interact with objects but not with documents. So, Mongoose becomes a bridge between Documents and Objects. Also, It provides lots of application logic, Such as schema validation.

What is the Node?

Official Definition: Node is a cross-platform runtime environment that allows developers to create various server-side tools and applications in JavaScript.

It means you can use Node to create a simple web server using the Node HTTP package.

Didn't get it? Here is the code:

// Load HTTP module
const http = require("http");

const hostname = "127.0.0.1";
const port = 8000;

// Create HTTP server
const server = http.createServer((req, res) => {

   // Set the response HTTP header with HTTP status and Content type
   res.writeHead(200, {'Content-Type': 'text/plain'});

   // Send the response body "Hello World"
   res.end('Hello World\n');
});

// Prints a log once the server starts listening
server.listen(port, hostname, () => {
   console.log(`Server running at http://${hostname}:${port}/`);
})

The Node creates the server for you. Mongoose is a driver that interacts with the database. Everything seems sorted, then Why the hell do we need an Express?

Web-development tasks don't directly support by Node. You have to add the specific handling for HTTP verbs (e.g. GET, POST, DELETE, etc.) with the URL Paths (also known as "Routes").

It can serve static HTML files, Or use templates to create an HTML response. Node won't be much of use on its own. You will have to write the whole code, or you can avoid inventing the wheel using a web framework.

What is the Express Framework?

Express is a web application framework. It is built on top of Node to provide a few out-of-box features, Such as methods to define route handlers for all the HTTP verbs.

Let's be more expressive through our code.

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello Express!')
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}!`)
});

Did you see it? Simpler code to make a server right.

What get method(verb) says? It's saying if the client(Browser) requests the route '/' on the server. I will send the response as "Hello Express" to the client.

CRUD Operations

CREATE

It means creating some resources on the database. Express has provided many HTTP methods such as post, put, and patch. We can use any of them to perform business logic, and it will create a specific resource based on that on the database.

app.post('/resource', async(req,res) => {
  const clientData = req.body // new data coming in the body object
 try{
    const doc = new Resource(clientData) // Creating an instance of Resource Model
    await doc.save(); // Inserted new document to MongoDB database
    res.status(201).json({success:true, data:doc})
  }catch(error){
    res.status(500).json({success:false, message:"Couldn't post new data", errorMessage:error.message})
  }
});

Understanding Part

  • Syntax: app.post(route, callbackFunction)

  • Client using HTTP verb POST says: I want to create a resource on the \resource route. Also, I am sending a new resource in the body of the Request (req) object.

  • Express App says: You can create the new resource using the callback function on \resource Route.

  • Why try-catch is used: Inserting a document into the MongoDB database is an asynchronous operation. It can go wrong in many places. So we are placing a try-catch as a guard to catch all the errors that doc.save() can throw.

READ

It means fetching resources from the database.

app.get('/resource', async (req,res) => {
  try{
    const data = await Resource.find({}) // Finding all documents from Resource Model
    res.status(200).json({success:true, data})
  }catch(error){
    res.status(500).json({success:false,message:"Couldn't fetch data", errorMessage:error.message})
  }
});

Understanding Part

  • Syntax: app.get(route, callbackFunction)

  • Client using HTTP verb GET says: I want to fetch all the resources from the /resource route.

  • Express App says: You can fetch all resources using callback function on `/resource` route.

  • find(): The method is provided by the Mongoose.

  • Why try-catch is used: Finding documents from the MongoDB database is an asynchronous operation. It can go wrong, so we are placing a try-catch as a guard to catch the errors that Resource.find() can throw.

UPDATE

It means updating the existing resource in the database.

app.post('/resource/:resourceId', async (req,res) => {
  const {resourceId} = req.params // getting resourceId on request params object
  try{
    const data = await Resource.findByID(resourceId) // Finding specific resource
    const modifiedData = data + some logic // Added business logic
    await modifiedData.save() // Saving modified data to DB
    res.status(201).json({success:true, data:modifiedData})
  }catch(error){
    res.status(500).json({success:false,message:"Couldn't modified data", errorMessage:error.message})
  }
});

Understanding Part

  • Syntax: app.post(route, callbackFunction)

  • Client using HTTP verb POST says: I want to create (update) the resource on /resource/:resourceId route.

  • Express App says: You can update the resources using the callback function on /resource/:resourceId Route.

  • findById() and save() methods are provided by Mongoose.

  • Why try-catch is used: Finding and saving documents is an asynchronous operation. It can go wrong, so we are placing a try-catch as a guard to catch those errors.

Delete

Delete All Resource

It means deleting all the resources from the specific route.

app.delete('\resource', async(req,res)=>{
  try{
    await Like.deleteMany({})
    res.status(200).json({deleted:true, success:true})
  }catch(error){
    res.status(500).json({deleted:false, success:false,message:"Couldn't delete all the resources",errorMessage:error.message})
  }
})

Understanding Part

  • Syntax: app.delete(route, callbackFunction)

  • Client using HTTP verb DELETE says: I want to delete the resource on /resource route.

  • Express App says: You can delete the resources using the callback function on /resource Route.

  • deleteMany(): It is an inbuilt method of Mongoose.

  • Why try-catch is used: Deleting the documents is an asynchronous operation. It can go wrong, so we are placing a try-catch as a guard to catch those errors.

Delete Specific Resource

It means deleting specific resources from the specific route.

app.delete('\resource\:resourceId', async(req,res)=>{
  const {resourceId} = req.params
  try{
    const foundDocument = await Resource.findById(resourceId)
    await foundDocument.remove()
    res.status(200).json({deleted:true, success:true, id:foundDocument._id})
  }catch(error){
    res.status(500).json({deleted:false, success:false, message:"Couldn't delete specific resource",errorMessage:error.message})
  }
})

Understanding Part

  • Syntax: app.delete(route, callbackFunction)

  • Client using HTTP verb DELETE says: I want to delete the resource on /resource/:resourceId route.

  • Express App says: You can delete the resources using the callback function on /resource/:resourceId Route.

  • findById() and remove(): These are inbuilt methods of Mongoose.

  • Why try-catch is used: Finding and deleting the documents is an asynchronous operation. It can go wrong, so we are placing a try-catch as a guard to catch those errors.

Endgame

In upcoming blogs, I will be using the Express middleware to simplify processes for our ease. Stay Tuned!