π Mini Project: Railway Ticket Booking System
π Features Covered
Create railway bookings
View bookings in browser
Filter by source & destination
Sort by journey date
Pagination (page-wise data)
Strong backend validations
Proper frontend β backend connectivity
π Folder Structure (IMPORTANT)
railway-booking-app/
β
βββ backend/
β βββ config/
β β βββ db.js
β β
β βββ models/
β β βββ Booking.js
β β
β βββ routes/
β β βββ bookingRoutes.js
β β
β βββ middlewares/
β β βββ errorHandler.js
β β
β βββ app.js
β βββ server.js
β
βββ frontend/
β βββ index.html
β βββ style.css
β βββ script.js
β
βββ package.json
βββ .env
π§ Backend Code (Node + Express + MongoDB)
1οΈβ£ package.json
{
"name": "railway-booking-app",
"version": "1.0.0",
"description": "Railway Booking Mini Project",
"main": "backend/server.js",
"scripts": {
"start": "node backend/server.js",
"dev": "nodemon backend/server.js"
},
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"mongoose": "^8.6.1"
}
}
2οΈβ£ .env
PORT=5000
MONGO_URI=mongodb://127.0.0.1:27017/railwayDB
3οΈβ£ backend/config/db.js
const mongoose = require("mongoose");
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI);
console.log("MongoDB Connected");
} catch (error) {
console.error("DB Error:", error.message);
process.exit(1);
}
};
module.exports = connectDB;
4οΈβ£ backend/models/Booking.js
π Day 27: Validations + Custom Validation
const mongoose = require("mongoose");
const bookingSchema = new mongoose.Schema(
{
passengerName: {
type: String,
required: true,
minlength: 3
},
age: {
type: Number,
required: true,
min: 5
},
source: {
type: String,
required: true
},
destination: {
type: String,
required: true
},
journeyDate: {
type: Date,
required: true,
validate: {
validator: function (value) {
return value > new Date();
},
message: "Journey date must be in the future"
}
},
trainNumber: {
type: String,
required: true
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Booking", bookingSchema);
5οΈβ£ backend/routes/bookingRoutes.js
π Day 26: Filtering, Sorting, Pagination
const express = require("express");
const Booking = require("../models/Booking");
const router = express.Router();
// CREATE booking
router.post("/", async (req, res, next) => {
try {
const booking = await Booking.create(req.body);
res.status(201).json(booking);
} catch (error) {
next(error);
}
});
// GET bookings (filter + sort + pagination)
router.get("/", async (req, res, next) => {
try {
const { source, destination, page = 1 } = req.query;
const filter = {};
if (source) filter.source = source;
if (destination) filter.destination = destination;
const limit = 5;
const skip = (page - 1) * limit;
const bookings = await Booking.find(filter)
.sort({ journeyDate: 1 })
.skip(skip)
.limit(limit);
res.json(bookings);
} catch (error) {
next(error);
}
});
module.exports = router;
6οΈβ£ backend/middlewares/errorHandler.js
const errorHandler = (err, req, res, next) => {
res.status(400).json({
error: err.message
});
};
module.exports = errorHandler;
7οΈβ£ backend/app.js
const express = require("express");
const cors = require("cors");
const bookingRoutes = require("./routes/bookingRoutes");
const errorHandler = require("./middlewares/errorHandler");
const app = express();
app.use(cors());
app.use(express.json());
app.use("/api/bookings", bookingRoutes);
app.use(errorHandler);
module.exports = app;
8οΈβ£ backend/server.js
require("dotenv").config();
const app = require("./app");
const connectDB = require("./config/db");
connectDB();
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
π¨ Frontend Code (HTML + CSS + JS)
9οΈβ£ frontend/index.html
<!DOCTYPE html>
<html>
<head>
<title>Railway Booking</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h2>Railway Ticket Booking</h2>
<form id="bookingForm">
<input type="text" placeholder="Passenger Name" id="name" required />
<input type="number" placeholder="Age" id="age" required />
<input type="text" placeholder="Source" id="source" required />
<input type="text" placeholder="Destination" id="destination" required />
<input type="date" id="date" required />
<input type="text" placeholder="Train Number" id="train" required />
<button type="submit">Book Ticket</button>
</form>
<h3>Bookings</h3>
<div id="bookings"></div>
<script src="script.js"></script>
</body>
</html>
π frontend/style.css
body {
font-family: Arial;
background: #f4f6f8;
padding: 20px;
}
form input, button {
display: block;
margin: 8px 0;
padding: 8px;
}
button {
background: #007bff;
color: white;
border: none;
}
.booking {
background: white;
padding: 10px;
margin-top: 10px;
border-radius: 4px;
}
1οΈβ£1οΈβ£ frontend/script.js
const API = "http://localhost:5000/api/bookings";
const form = document.getElementById("bookingForm");
const bookingsDiv = document.getElementById("bookings");
form.addEventListener("submit", async (e) => {
e.preventDefault();
const data = {
passengerName: name.value,
age: age.value,
source: source.value,
destination: destination.value,
journeyDate: date.value,
trainNumber: train.value
};
await fetch(API, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
loadBookings();
form.reset();
});
async function loadBookings() {
const res = await fetch(API);
const bookings = await res.json();
bookingsDiv.innerHTML = "";
bookings.forEach(b => {
bookingsDiv.innerHTML += `
<div class="booking">
<b>${b.passengerName}</b> | ${b.source} β ${b.destination}<br/>
Train: ${b.trainNumber} | Date: ${new Date(b.journeyDate).toDateString()}
</div>
`;
});
}
loadBookings();
π― Concepts Covered (Mapping with Day 26 & 27)
| Concept | Where Used |
| Filtering | source, destination query |
| Sorting | .sort({ journeyDate: 1 }) |
| Pagination | skip() + limit() |
| Validation | Schema rules |
| Custom Validation | Future journey date |
| Frontend UI | HTML/CSS/JS |
| API Connectivity | fetch() |
π§ Student Tasks (VERY IMPORTANT)
1οΈβ£ Add filter dropdown for source & destination
2οΈβ£ Add page buttons (Next / Prev)
3οΈβ£ Show validation error messages on UI
4οΈβ£ Add delete booking feature
5οΈβ£ Add total bookings count
π Stay Connected
If you found this article helpful and want to receive more such beginner-friendly and industry-relevant Node JS notes, tutorials, and project ideas β π© Subscribe to our newsletter by entering your email below.
And if you're someone who wants to prepare for tech interviews while having a little fun and entertainment, π₯ Donβt forget to subscribe to my YouTube channel β Knowledge Factory 22 β for regular content on tech concepts, career tips, and coding insights!
Stay curious. Keep building. π

