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
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"
}
}
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;
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;
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);
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);
})
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);
});
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);
})
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);
});
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.
Top comments (4)
Is a good intro thanks. Needs an update tho as you listed delete operation twice and missed create!
Hi John, thank you for letting me know! I just updated it!
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.
Hi, I am, but I can't DM you if you don't follow me I think :/ linkedin.com/in/dubymarjtr/