Creating a URL shortener service is a great way to dive into full-stack development with Node.js and MongoDB. In this blog, we’ll walk through the process of building a URL shortener application, which allows users to convert long URLs into shortened versions and track their usage.
Prerequisites
To follow this tutorial, you should have:
Node.js installed
Basic knowledge of JavaScript and Express.js
A MongoDB database (you can use MongoDB Atlas for a cloud solution)
Project Setup
Step 1: Initialize the Project
First, create a new directory for your project and initialize it with npm:
cd url-shortener-app
npm init -y
Step 2: Install Dependencies
Next, install the necessary dependencies:
npm install –save-dev nodemon
Step 3: Project Structure
Create the following folder structure:
├── controllers/
│ └── urlController.js
├── models/
│ └── urlModel.js
├── routes/
│ └── urlRoutes.js
├── .env
├── index.js
├── package.json
Building the Backend
Step 4: Set Up Express Server
In the index.js file, set up the Express server and connect to MongoDB:
const mongoose = require(‘mongoose‘);
const urlRoutes = require(‘./routes/urlRoutes‘);
const cors = require(‘cors‘);
const app = express();
app.use(express.json());
require(“dotenv“).config();
const dbUser = process.env.MONGODB_USER;
const dbPassword = process.env.MONGODB_PASSWORD;
// Connect to MongoDB
mongoose
.connect(
`mongodb+srv://${dbUser}:${dbPassword}@cluster0.re3ha3x.mongodb.net/url-shortener-app`,
{ useNewUrlParser: true, useUnifiedTopology: true }
)
.then(() => {
console.log(“Connected to MongoDB database!“);
})
.catch((error) => {
console.error(“Connection failed!“, error);
});
app.use(cors({
origin: “*“,
}));
app.get(‘/‘, (req, res) => {
res.send(‘Welcome to URL Shortener API‘);
});
app.use(‘/api‘, urlRoutes);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Create a .env file in the root directory to store environment variables:
MONGODB_PASSWORD=yourMongoDBPassword
Step 5: Define the URL Model
In the models/urlModel.js file, define the schema for URLs:
const urlSchema = new mongoose.Schema({
originalUrl: { type: String, required: true },
shortUrl: { type: String, required: true, unique: true },
clicks: { type: Number, default: 0 },
expirationDate: { type: Date },
createdAt: { type: Date, default: Date.now },
});
module.exports = mongoose.model(‘Url‘, urlSchema);
Step 6: Create Routes
In the routes/urlRoutes.js file, define the routes for the API:
const { createShortUrl, redirectUrl, getUrls, getDetails, deleteUrl } = require(‘../controllers/urlController‘);
const router = express.Router();
router.post(‘/shorten‘, createShortUrl);
router.get(‘/urls‘, getUrls);
router.get(‘/:shortUrl‘, redirectUrl);
router.get(‘/details/:shortUrl‘, getDetails);
router.delete(‘/delete/:shortUrl‘, deleteUrl);
module.exports = router;
Step 7: Implement Controllers
In the controllers/urlController.js file, implement the controller functions:
function generateUniqueId(length) {
const characters = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789‘;
let result = ”;
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
result += characters[randomIndex];
}
return result;
}
const createShortUrl = async (req, res) => {
const { originalUrl } = req.body;
const shortUrl = generateUniqueId(5);
const urlRegex = new RegExp(/^(http|https)://[^ “]+$/);
if (!urlRegex.test(originalUrl))
return res.status(400).json(‘Invalid URL‘);
const url = await Url.findOne({ originalUrl });
if (url) {
res.json(url);
return;
}
const expirationDate = new Date();
expirationDate.setDate(expirationDate.getDate() + 7);
const newUrl = new Url({ originalUrl, shortUrl, expirationDate });
await newUrl.save();
res.json(newUrl);
};
const redirectUrl = async (req, res) => {
const { shortUrl } = req.params;
const url = await Url.findOne({ shortUrl });
if (!url || (url.expirationDate && url.expirationDate < new Date())) {
res.status(404).json(‘URL expired or not found‘);
return;
}
url.clicks++;
await url.save();
res.redirect(url.originalUrl);
};
const getUrls = async (req, res) => {
try {
const urls = await Url.find({}).sort({ _id: –1 });
res.json(urls);
} catch (error) {
res.status(500).json({ message: ‘Server Error‘ });
}
};
const getDetails = async (req, res) => {
try {
const { shortUrl } = req.params;
const url = await Url.findOne({ shortUrl });
if (url) {
res.json(url);
} else {
res.status(404).json(‘URL not found‘);
}
} catch (error) {
res.status(500).json({ message: ‘Server Error‘ });
}
};
const deleteUrl = async (req, res) => {
try {
const { shortUrl } = req.params;
await Url.findOneAndDelete({ shortUrl });
res.json(‘URL deleted‘);
} catch (error) {
res.status(500).json({ message: ‘Server Error‘ });
}
};
module.exports = { createShortUrl, redirectUrl, getDetails, getUrls, deleteUrl };
Running the Application
Start the server using the following command:
This command will start your server with Nodemon, which will automatically restart the server when you make changes to your code.
Conclusion
In this blog, we’ve built a simple URL shortener application using Node.js and MongoDB. This application allows users to shorten URLs, track their usage, and manage them with expiration dates. This project is a great starting point for learning about full-stack development and can be expanded with additional features such as user authentication, custom URL aliases, and more.
Exploring the Code
Visit the GitHub repository to explore the code in detail.
Feel free to customize the blog according to your preferences and provide more details or explanations where needed.