DEV Community

Dubymar Tollinchi
Dubymar Tollinchi

Posted on • Updated on

Building an Express back-end for basic CRUD operations

When enrolling for college, I had to choose between Web Development and Web Design. This decision was quite easy because I thought "making a website look pretty is something that most developers can do (not saying it's easy tho!), but making a website be completely functional? That's more of a complex job, and that's a challenge I want to take".

In my Web Technologies class, after learning the basics of JavaScript and working with front-end, it was time to swim into the deep waters of the back-end of a website. I was assigned to create RESTful routes that interact with a MongoDB database using Node.js and Express.js. It was very confusing at the beginning, but after building a few small projects applying the same steps, I feel more comfortable to share the knowledge I acquired with this community.

So let's dive into it!!

The first thing we need to know about is Node.js, and I already wrote a post about it, so go check that out so you understand why and how it is used. After installing Node, we will use the terminal to install the required dependencies, in this case are: dotenv, express, and mongodb. Luckily, I used a template that already had all these installed, but if your project does not have any of these, just type npm install express on the terminal, repeating the same syntax with the other packages.

The second step is to create a .env file, which will contain the database URL that will connect our application to MongoDB. This file will be untracked, since we do not want to include it in our commits. This is more of a security reason, because why will we want strangers accessing to our database, right?

DB_CLIENT_URL=databaseurl
Enter fullscreen mode Exit fullscreen mode

The third step is to go into our config.js file and declare the configurations for our project. In this case, I have the port, database URL, name, and collection name. Having this information here and not in other files will make our website easier to maintain, having to change it just here and not everywhere.

export default {
  port: process.env.PORT || 3000,
  db: {
    clientURL: process.env.DB_CLIENT_URL,
    name: "sample_airbnb",
    collectionName: "listingsAndReviews"
  }
}
Enter fullscreen mode Exit fullscreen mode

As you can notice, there is no way to see the actual database URL. For this project I used an Airbnb database sample from MongoDB, but in case I want to use another database, I can change the name and collection right there and that will be applied to the entire project.

The fourth step is to create a db/conns (database connections) folder, and inside create a client.js file, that will contain a reusable Mongo client to connect to our application. Here is where we use that mongodb package that we installed earlier. Note: this is the only file inside of that folder, everything else from now on will continue to exist inside the server folder.

import { MongoClient } from "mongodb";
import config from "./config.js";

const client = new MongoClient(config.db.clientURL);

client.connect()
  .then(() => {
    console.info("MongoDB Client 🏃🏾‍♂️");
  })
  .catch((err) => {
    console.error("Error starting MongoDB Client", err.message);
    // Exit process with failure
    process.exit(1);
  });
process.on("SIGINT", () => {
  client.close().then(() => {
    console.info("MongoDB Client disconnected");
    process.exit(0);
  });
});
export default client;
Enter fullscreen mode Exit fullscreen mode

Once we have our Mongo Client successfully connecting to our database, we can proceed to create our routes in the router.js file. First, we will start with a test route to connect to our API. We need to import the content from config.js, client.js, and our Router from express.

import Router from "express";
import config from "./config.js";
import client from "./db/conns/client.js";

// create collection variable to reduce code duplication
const collection = client
.db(config.db.name)
.collection(config.db.collectionName);

const router = new Router();

// localhost:3000/api
router.get("/", (_, res) => {
    res.send("Hello from API router");
});

export default router;
Enter fullscreen mode Exit fullscreen mode

To utilize this router we need to import it to our index.js file, using express as the framework that will make our lives easier. Express gives developers all the tools they need to create HTTP servers, allowing to receive and send data as JSON.

import express from "express";
import config from "./config.js";
import router from "./router.js";

const app = express();

// json middleware allows to send and receive JSON data
app.use(express.json());

app.get("/", (_, res) => {
  res.send("Hello World");
});

app.use("/api", router);
Enter fullscreen mode Exit fullscreen mode

To run our server we can type npm start in our terminal, and then go to any explorer and type http://localhost:3000/api and that will show "Hello from API router". Now that our testing route is working, we can proceed to create the rest of our routes. In this project we are using basic CRUD operations, which are Create, Read, Update, and Delete. In some of these route we will need to use Insomnia. These platform will allow us to send JSON data, since we are not doing that from the browser. The way we will send this information will be on the request body.

Let's start with the first route, which will be create a listing.

// post a new listing
router.post("/listings", async (req,res) => {
    const newListing = await collection.insertOne(req.body);
    res.json(newListing);
})
Enter fullscreen mode Exit fullscreen mode

The second route will allow to read all listings. In this case, the {} inside the find method brings all listing, but we can also add any filters that we want inside {}. Let's have in mind that these filters must be in the MongoDB language, which is different from a later update of these route where we have optional filters, using in that case JavaScript filters.

// get all listings
router.get("/listings", async (_, res) => {
    const listingsData = await collection.find({}).toArray();
    res.json(listingsData);
});
Enter fullscreen mode Exit fullscreen mode

The third one will take a listing id and update that listing. In the Insomnia body we can send the "payload", which is the updated data for our listing.

// update a listing
router.put("/listings/", async (req, res) => {
    const updatedListing = await collection.updateOne({ _id: req.body.id},
    { $set: req.body.payload });
    res.json(updatedListing);
})
Enter fullscreen mode Exit fullscreen mode

And the fourth one to complete our CRUD operations is to delete a listing using its id.

// delete a listing
router.delete("/listings/:id", async (req, res) => {
    const deletedListing = await collection.deleteOne({ _id: req.params.id });
    res.json(deletedListing);
});
Enter fullscreen mode Exit fullscreen mode

This project has more routes, such as reading an specific listing, getting all reviews from one listing, creating, updating and deleting a review from one listing. For your reference, this is the project repo.

These basic routes allow us to perform CRUD operations in our database, and although it is just a server-side project, this gives you an idea on how to create a full-stack website, if you already know how to connect to the client-side. Node.js and Express.js made possible to create and work with the server without knowing any other server-side language, such as PHP.

Oldest comments (4)

Collapse
 
spataroinc profile image
Daniel Spataro

DM me on Twitter/Linkedin if you'd be interested in joining Buildable.dev as a part-time/freelance technical writer, Dubymar! Love your stuff.

Collapse
 
dubymarjtr profile image
Dubymar Tollinchi

Hi, I am, but I can't DM you if you don't follow me I think :/ linkedin.com/in/dubymarjtr/

Collapse
 
johnkazer profile image
John Kazer

Is a good intro thanks. Needs an update tho as you listed delete operation twice and missed create!

Collapse
 
dubymarjtr profile image
Dubymar Tollinchi

Hi John, thank you for letting me know! I just updated it!