In this tutorial, we will build a CRUD RESTful API using Expressjs, a popular web framework for Node.js, and MongoDB, a NoSQL database, with Mongoose, an elegant MongoDB object modeling tool.

This guide will cover setting up the server, connecting to MongoDB, and routing with Express.

Setting Up the Server

First, we need to set up our Express server and include the necessary middleware:

const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

const Contact = require("./routes/Contact");

app.use("/api", Contact);

const port = 3000;
app.listen(port, () => {
    console.log("Server started successfully");
});

Here, we import the express, mongoose, and body-parser modules. We initialize the Express application and configure it to use body-parser for parsing JSON and URL-encoded data. We also import our Contact routes and set up the server to listen on port 3000.

Connecting to MongoDB

Now, we need to connect our application to a MongoDB database. Add the following code to your main server file:

// Connection from Mongoose to MongoDB
const connectToDB = async () => {
    try {
        await mongoose.connect('mongodb://localhost:27017/mydatabase', {
            useNewUrlParser: true,
            useUnifiedTopology: true,
            autoIndex: true, //make this also true
        });
        console.log("Connected to MongoDB");
    } catch (error) {
        console.log(error);
        process.exit(1);
    }
}

connectToDB();

This code defines an asynchronous function connectToDB that connects to a MongoDB database using Mongoose. If the connection is successful, a message is logged to the console. If there’s an error, it is logged, and the process exits.

Creating the Contact Model

Next, we need to create the Contact model. Create a new file named Contact.js inside a models directory:

In the Contact.js file, we define the schema for the Contact model.

This schema outlines the structure of a contact document in MongoDB, including fields for name, email, phone, and message. We also enable timestamps to automatically track when documents are created or modified.

const mongoose = require("mongoose");

const contactSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true,
        trim: true
    },
    email: {
        type: String,
        required: true,
        trim: true,
        lowercase: true,
        unique: true
    },
    phone: {
        type: String,
        required: true,
        trim: true
    },
    message: {
        type: String,
        required: true,
        trim: true
    }
}, {
    timestamps: true
});

const Contact = mongoose.model("Contact", contactSchema);

module.exports = Contact;

Defining the Contact Routes

Next, we need to define the routes for our API. Create a new file named Contact.js inside a routes directory:

See also  React Native Developer: Skills, Roles, and Responsibilities

Setting Up Express Router

First, we need to set up our Express router and import the Contact model:

const express = require("express");
const router = express.Router();
const Contact = require("../models/Contact");

Here, we import the express module and create a new router using express.Router(). We also import the Contact model, which we will use to interact with our MongoDB database.

Creating a New Contact (POST)

To handle the creation of a new contact, we define a POST route:

// Create a new contact
router.post("/contacts", async (req, res) => {
    try {
        const contact = new Contact(req.body);
        await contact.save();
        res.status(201).send(contact);
    } catch (error) {
        res.status(400).send(error);
    }
});

This route listens for POST requests at the /contacts endpoint. It creates a new Contact instance using the data from the request body (req.body).

The new contact is then saved to the database with contact.save(). If successful, the server responds with the created contact and a status code of 201 (Created).

If there’s an error, it responds with a status code of 400 (Bad Request) and the error message.

Retrieving All Contacts (GET)

To retrieve all contacts from the database, we define a GET route:

// Get all contacts
router.get("/contacts", async (req, res) => {
    try {
        const contacts = await Contact.find({});
        res.status(200).send(contacts);
    } catch (error) {
        res.status(500).send(error);
    }
});

This route listens for GET requests at the /contacts endpoint. It uses Contact.find({}) to retrieve all contacts from the database. If successful, it responds with the list of contacts and a status code of 200 (OK). If there’s an error, it responds with a status code of 500 (Internal Server Error) and the error message.

See also  Top 30 Jest Interview Questions and Answers

Retrieving a Single Contact by ID (GET)

To retrieve a specific contact by its ID, we define another GET route:

// Get a contact by ID
router.get("/contacts/:id", async (req, res) => {
    try {
        const contact = await Contact.findById(req.params.id);
        if (!contact) {
            return res.status(404).send();
        }
        res.status(200).send(contact);
    } catch (error) {
        res.status(500).send(error);
    }
});

This route listens for GET requests at the /contacts/:id endpoint, where :id is a placeholder for the contact’s ID. It uses Contact.findById(req.params.id) to find the contact by its ID.

If the contact is found, it responds with the contact and a status code of 200 (OK). If the contact is not found, it responds with a status code of 404 (Not Found). If there’s an error, it responds with a status code of 500 (Internal Server Error) and the error message.

Updating a Contact (PUT)

To update an existing contact, we define a PUT route:

// Update a contact
router.put("/contacts/:id", async (req, res) => {
    try {
        const contact = await Contact.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
        if (!contact) {
            return res.status(404).send();
        }
        res.status(200).send(contact);
    } catch (error) {
        res.status(400).send(error);
    }
});

This route listens for PUT requests at the /contacts/:id endpoint. It uses Contact.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true }) to update the contact by its ID with the new data from the request body. The { new: true, runValidators: true } options ensure that the updated document is returned and that validation is run on the update. If the contact is found and updated, it responds with the updated contact and a status code of 200 (OK). If the contact is not found, it responds with a status code of 404 (Not Found). If there’s an error, it responds with a status code of 400 (Bad Request) and the error message.

See also  Top 30 JavaScript Functions Interview Questions Answers

Deleting a Contact (DELETE)

To delete a contact, we define a DELETE route:

// Delete a contact
router.delete("/contacts/:id", async (req, res) => {
    try {
        const contact = await Contact.findByIdAndDelete(req.params.id);
        if (!contact) {
            return res.status(404).send();
        }
        res.status(200).send(contact);
    } catch (error) {
        res.status(500).send(error);
    }
});

This route listens for DELETE requests at the /contacts/:id endpoint. It uses Contact.findByIdAndDelete(req.params.id) to find the contact by its ID and delete it.

If the contact is found and deleted, it responds with the deleted contact and a status code of 200 (OK).

If the contact is not found, it responds with a status code of 404 (Not Found). If there’s an error, it responds with a status code of 500 (Internal Server Error) and the error message.

——————————————————————————————————-

In this tutorial, we’ve built a RESTful API using Express.js and MongoDB with Mongoose.

We set up the server, defined routes for CRUD operations, created a Mongoose model, and connected to the database. This setup provides a solid foundation for building more complex applications with robust data management capabilities.

By understanding and implementing these principles, you can create scalable and maintainable APIs for your projects.

By soorya