DEV Community

Victor Peter
Victor Peter

Posted on

CRUD with ExpressJS and MongoDB (Typescript)

Introduction

As a backend developer seeking to create APIs, you'll want to learn about how to store and retrieve data from the database your API works with. Learning all these may seem overwhelming, but, I will show you how to write a CRUD operation API in this article. Before we get our hands dirty, let's talk about some few terms that we need to be clear about.

What is an API?

The full meaning of API is Application Program Interface. An API is simply an interface that can be used by an application program to communicate with a service. E.g, your phone application needs to connect to a service to retrieve information, usually, that service may not be written with the same language your mobile app is written in, so, there need to be an interface which your mobile app can interact with to make the service understand the request that the mobile app is making. That interface is the API and your mobile app is the the program trying to interact with that services' interface.

What is the backend?

The backend comprises of the API, the database, load balancers, process managers and other technologies that enables or enhances the functionality of the service.

What are RESTful APIs?

RESTful means Representational State Transfer and it's a kind of API that ensures stateless interactions with programs using it.

Let me explain: In real life, an example of a stateless transaction would be going to your office without an ID card when the policy at your office demands that you show your ID card before you're allowed into the premises. In this case, even if the gate keeper knows you're an employee, he/she wont still let you in until you show your ID card. And even if you're with your ID card and you step out for just a minute, to get back in to the company's premises you have to show your ID card.

That's exactly how RESTful APIs behave. They don't keep any context/record about your previous interactions with them, once you send a request to a RESTful API and it sends back a response, the connection established when you sent the request is closed. When another request comes in, it's treated as a fresh request (a new connection is established between the program and the server and is closed after the server sends a response).

Some features of RESTful APIs are: HTTP methods, request headers, request payloads, endpoints, response headers, response data, status codes, etc.

Database

A database is simply a server that is dedicated to storing information permanently except the information is being deleted. Your API isn't designed to keep information permanently, so there has to be a place to store it, that's where the database comes in.

MongoDB

MongoDB is coined from the word "humongous", which reflects it's ability to handle large amount of data. It's a schemaless database, which means you can store your data as you like.

Mongoose

You can also use an ODM (Object Document Mapper) like Mongoose to create and appy application level schema. MongoDB stores data as documents, has collections that are made up of documents. Mongoose is an ODM that enables developers query mongodb and also maintain schemas to be used with the database.

CRUD Operations

CRUD stands for Create, Read, Update and Delete. These are the basic operations you'll come across as a backend developer/engineer.

ExpressJS

ExpressJS or Express is a framework that was built to enable developers (like you and I) to build APIs seamlessly.

Let's begin setting up.

Step 1: Initialize a project/package

You initialize a project or package by running the command:

npm init -y
Enter fullscreen mode Exit fullscreen mode

This will create a package.json file that will be used by npm to manage your project's dependencies.

Step 2: Install the necessary dependencies which are morgan, ExpressJS, Mongoose cors and nodemon

I've already talked about expressjs and mongoose, so let's talk about other dependencies briefly.

Morgan is used to generate logs that can be used for different purposes, like printing out the logs to the console when the server is running.

Cors is an acronym that means Cross-origin resource sharing, this package/dependency is necessary when you want to restrict which program can interact with your interface and what type of request methods, etc the programs can send to your API.
This is important when your the program and your API are runnng on different platforms or different ports.

Nodemon is a dependency that monitors your project files for changes and automatically restarts the server once there is a change to any file being watched by nodemon. Think of nodemon as node monitor ;).
Note: You shouldn't use nodemon on a production server, except you're part of the developers that attempt fix bug in production, lol.

Typescript is used to provides types and interfaces to your code.

You install morgan, cors, nodemon, express, mongoose and typescript by running the command:

npm install morgan cors nodemon typescript mongoose express
Enter fullscreen mode Exit fullscreen mode

Also run the code below to install the type defination for morgan:

npm i --save-dev @types/morgan @types/express @types/cors
Enter fullscreen mode Exit fullscreen mode

After that initialize typescript on the project by running the code:

tsc --init
Enter fullscreen mode Exit fullscreen mode

Step 3: Create the files necessary for the project

On your project's root folder (the folder where the package.json is located) create the following files: index.ts, crud.ts and crudModel.ts.

The index.ts file will be used as the entryp point file (the file that gets executed first when the service is starting up).

The crud.ts file will be used to store all the routes and controllers that will be available to users make the requests with.

The crudModel.ts file which will be used to keep the schema that will be used to enforce data consistency with the collection of records we want to work with.

Step 4: Paste the following into your index.js file

import express, {Application} from "express";
import mongoose from "mongoose";
import logger from "morgan";
import cors from "cors";
import crudRoutes from "./crud";

const app: Application = express();

mongoose.connect("mongodb://localhost:27017/crud").then(() => {
    console.log("Connected to database");
}).catch((error) => {
    console.log("Error:", error);
});

app.use(logger("dev"));
app.use(cors({ origin: "*" }));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.use("/crud", crudRoutes);

app.use(function (req, res, next) {
    res.status(404).send({
        message: "Route not found"
    });
  });

app.listen(4000, () => {
    console.log("The server is up...");
});
Enter fullscreen mode Exit fullscreen mode

Step 5: Paste the following into your crud.ts file

import {Router, Request, Response} from "express";
import { contactsCollection } from "./crudModel";

const routes = Router();

routes.post("/contact", async (req: Request, res: Response) => {
    const {fullName, phoneNumber} = req.body;

    const contact = await contactsCollection.create({fullName, phoneNumber});

    res.status(201).send({
        message: "New contact created successfully",
        data: contact
    });
});

routes.get("/contacts", async (req: Request, res: Response) => {
    const {fullName, phoneNumber} = req.body;

    const contact = await contactsCollection.find({});

    res.send({
        message: "All contact retrieved successfully",
        data: contact
    });
});

routes.get("/contacts/:id", async (req: Request, res: Response) => {
    const {id} = req.params;

    const contact = await contactsCollection.findById(id);

    res.send({
        message: "Contact retrieved successfully",
        data: contact
    });
});

routes.get("/contacts/:phoneNumber", async (req: Request, res: Response) => {
    const {phoneNumber} = req.params;

    const contact = await contactsCollection.findOne({phoneNumber});

    res.send({
        message: "Contact retrieved successfully",
        data: contact
    });
});

routes.put("/contacts/:id", async (req: Request, res: Response) => {
    const {id} = req.params;

    const {fullName, phoneNumber} = req.body;

    const contact = await contactsCollection.findByIdAndUpdate(id, {
        fullName, phoneNumber
    }, {new: true});

    res.send({
        message: "Contact updated successfully",
        data: contact
    });
});

routes.patch("/contacts/:id", async (req: Request, res: Response) => {
    const {id} = req.params;

    const {fullName} = req.body;

    const contact = await contactsCollection.findByIdAndUpdate(id, {
        fullName
    }, {new: true});

    res.send({
        message: "Contact updated successfully",
        data: contact
    });
});

routes.delete("/contacts/:id", async (req: Request, res: Response) => {
    const {id} = req.params;


    const contact = await contactsCollection.findByIdAndDelete(id);

    res.send({
        message: "Contact deleted successfully",
        data: contact
    });
});

export default routes;
Enter fullscreen mode Exit fullscreen mode

Step 6: Paste the following code into your crudModel.ts file

import {Schema, model} from "mongoose";

const myContactsSchema = new Schema({
    fullName: {
        type: String,
        required: true
    },
    phoneNumber: {
        type: String,
        required: true
    }
}, {timestamps: true});

const contactsCollection = model("contacts", myContactsSchema);

export {
    contactsCollection
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Modify your package.json file

"scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "start": "nodemon index.js"
  }

Enter fullscreen mode Exit fullscreen mode

Step: 8: Install "Rest Client" extension.

Image description

Step 9: Open up your terminal and type npm start. This should startup your server automatically. The result should look like this:

Image description

Step 10: Test the API.

You could use postman to test the API, but a more convenient (IMO) option would be to use rest client, so in your root folder, create a test.rest file and paste the following into it:

POST http://localhost:4000/crud/contact
Content-Type: application/json

{
    "fullName": "Jimmy wire wire",
    "phoneNumber": "081122222211111"
}

###

GET http://localhost:4000/crud/contacts
Content-Type: application/json

###

GET http://localhost:4000/crud/contacts/676f654d7872dbd2f49aee48
Content-Type: application/json

###

PUT http://localhost:4000/crud/contacts/676f654d7872dbd2f49aee48
Content-Type: application/json

{
    "fullName": "Victor Ukok",
    "phoneNumber": "0811111111211"
}

###

PATCH http://localhost:4000/crud/contacts/676f654d7872dbd2f49aee48
Content-Type: application/json

{
    "fullName": "Victor Ukok edited"
}

###

DELETE http://localhost:4000/crud/contacts/676f6638b3383ee1f50955f1

Enter fullscreen mode Exit fullscreen mode

The result should look like this:

Image description

Conclusion

This API can be deployed on platforms like render.com , documented on postman and made available to the public if you want to take it to that extent. I hope you learnt about how to conduct CRUD operations using APIs? Hit me up if you have any question/questions.

Top comments (0)