Week # 10: DevOps Learning Journey - Building a URL Shortener with Node.js, MongoDB, and EJS(Deploy on AWS)
In this blog, we’ll dive into the process of creating a URL shortener using Node.js, Express, MongoDB, and EJS. We’ll explain the workflow, demonstrate key pieces of code, and guide you through the setup process.
Features of the URL Shortener
Generate short, unique URLs.
Store original and shortened URLs in MongoDB.
Redirect users to the original URL when visiting the short link.
Track the number of visits for each shortened URL.
Tools and Technologies
Here’s the tech stack and packages we used:
Node.js: For building the server-side logic.
MongoDB: For database storage of URLs and analytics.
EJS: As the templating engine for rendering dynamic HTML.
shortid/nanoid: For generating unique short IDs for URLs.
Project Setup and Workflow
1. Initializing the Project
Start by creating a Node.js project and installing the required dependencies:
npm init -y
npm install express mongoose ejs nanoid shortid
2. Folder Structure
The project follows an MVC architecture:
plaintextCopy codeproject/
├── controllers/
│ └── url.js
├── models/
│ └── url.js
├── routes/
│ ├── url.js
│ └── staticRouter.js
├── views/
│ ├── home.ejs
│ └── analytics.ejs
├── index.js
├── connect.js
└── package.json
Code Walkthrough
Database Connection (connect.js
)
Connect to the MongoDB cluster:
const mongoose = require('mongoose');
async function connectToMongoDB(uri) {
return mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true });
}
module.exports = { connectToMongoDB };
URL Schema and Model (models/url.js
)
Defines the structure for storing URLs:
const mongoose = require('mongoose');
const urlSchema = new mongoose.Schema({
shortId: { type: String, required: true, unique: true },
redirectURL: { type: String, required: true },
visitHistory: [{ timeStamp: { type: Number } }],
}, { timestamps: true });
const URL = mongoose.model("url", urlSchema);
module.exports = URL;
Controller Logic (controllers/url.js
)
Handles the core functionalities:
Generate Short URL
const shortid = require('shortid'); const URL = require('../models/url'); async function handleGenrateNewShortURL(req, res) { const body = req.body; if (!body.url) return res.status(400).json({ error: 'URL is required' }); const shortID = shortid.generate(); await URL.create({ shortId: shortID, redirectURL: body.url, visitHistory: [] }); return res.render('home', { id: shortID }); }
Redirect and Track Visits
async function handleGetAnalytics(req, res) { const shortId = req.params.shortId; const result = await URL.findOne({ shortId }); return res.json({ totalClicks: result.visitHistory.length, analytics: result.visitHistory }); } module.exports = { handleGenrateNewShortURL, handleGetAnalytics, };
Routes (routes/url.js
)
Defines API endpoints for URL generation and analytics:
const express = require('express');
const { handleGenrateNewShortURL, handleGetAnalytics } = require('../controllers/url');
const router = express.Router();
router.post("/", handleGenrateNewShortURL);
router.get("/analytics/:shortId", handleGetAnalytics);
module.exports = router;
Main Server File (index.js
)
Sets up the Express application and configures routes:
const express = require('express');
const app = express();
const path = require('path');
const { connectToMongoDB } = require('./connect');
const urlRoute = require('./routes/url');
app.set("view engine", "ejs");
app.set("views", path.resolve("./views"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
connectToMongoDB("YOUR_MONGO_URI").then(() => {
console.log("Connected to MongoDB");
});
app.use("/url", urlRoute);
app.listen(8001, () => {
console.log("Server running on PORT 8001");
});
Dynamic Templates with EJS
Home Template (
views/home.ejs
):
Displays the short URL:<h1>Your Shortened URL</h1> <p><a href="/url/<%= id %>">localhost:8001/url/<%= id %></a></p>
Analytics Page (
views/analytics.ejs
):
Shows analytics data.
Workflow Explanation
User Input: The user submits a URL through a form.
Short URL Creation:
The server generates a unique short ID usingshortid
and stores it in the database with the original URL.Redirection:
When a user accesses the short URL, the server redirects them to the original URL and logs the visit.Analytics:
A separate endpoint allows users to view analytics like the number of clicks and timestamps.
Deploy and Test
Start the application locally:
nodemon index.js
This project demonstrates fundamental concepts of web development, MVC architecture, and database integration. Modify and scale it to suit your needs!