Perfect 🚖 — let’s design a Taxi Booking App Backend (like Uber, Rapido) for practice.
This kind of project is real-world and advanced: it involves authentication, geolocation, ride booking, role-based access, and real-time status updates.
🚀 Example 4: Taxi Booking Backend (Uber/Rapido Clone)
📂 Project Structure
taxi-app-backend/
│── src/
│ ├── config/
│ │ └── db.js
│ ├── controllers/
│ │ ├── authController.js
│ │ ├── rideController.js
│ │ └── driverController.js
│ ├── middleware/
│ │ ├── authMiddleware.js
│ │ └── errorMiddleware.js
│ ├── models/
│ │ ├── User.js
│ │ ├── Driver.js
│ │ └── Ride.js
│ ├── routes/
│ │ ├── authRoutes.js
│ │ ├── rideRoutes.js
│ │ └── driverRoutes.js
│ ├── app.js
│ └── server.js
│── .env
│── package.json
📦 Install Dependencies
npm init -y
npm install express bcryptjs jsonwebtoken dotenv mongoose
npm install joi helmet cors morgan socket.io
npm install nodemon --save-dev
⚙️ src/config/db.js
const mongoose = require("mongoose");
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI);
console.log("MongoDB connected");
} catch (err) {
console.error(err.message);
process.exit(1);
}
};
module.exports = connectDB;
👤 src/models/User.js
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, unique: true, required: true },
password: { type: String, required: true },
role: { type: String, enum: ["Rider", "Driver", "Admin"], default: "Rider" },
}, { timestamps: true });
module.exports = mongoose.model("User", userSchema);
🚖 src/models/Driver.js
const mongoose = require("mongoose");
const driverSchema = new mongoose.Schema({
user: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true },
vehicleNumber: { type: String, required: true },
isAvailable: { type: Boolean, default: true },
currentLocation: {
lat: { type: Number },
lng: { type: Number }
}
}, { timestamps: true });
module.exports = mongoose.model("Driver", driverSchema);
🏁 src/models/Ride.js
const mongoose = require("mongoose");
const rideSchema = new mongoose.Schema({
rider: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true },
driver: { type: mongoose.Schema.Types.ObjectId, ref: "Driver" },
pickup: {
lat: { type: Number, required: true },
lng: { type: Number, required: true }
},
drop: {
lat: { type: Number, required: true },
lng: { type: Number, required: true }
},
status: {
type: String,
enum: ["Requested", "Accepted", "Ongoing", "Completed", "Cancelled"],
default: "Requested"
},
fare: { type: Number }
}, { timestamps: true });
module.exports = mongoose.model("Ride", rideSchema);
🔑 src/controllers/authController.js
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const User = require("../models/User");
exports.register = async (req, res, next) => {
try {
const { name, email, password, role } = req.body;
const hashed = await bcrypt.hash(password, 10);
const user = await User.create({ name, email, password: hashed, role });
res.status(201).json({ message: "User registered", user });
} catch (err) {
next(err);
}
};
exports.login = async (req, res, next) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) return res.status(401).json({ message: "Invalid credentials" });
const valid = await bcrypt.compare(password, user.password);
if (!valid) return res.status(401).json({ message: "Invalid credentials" });
const token = jwt.sign({ id: user._id, role: user.role }, process.env.JWT_SECRET, {
expiresIn: "1h",
});
res.json({ token });
} catch (err) {
next(err);
}
};
📲 src/controllers/rideController.js
const Ride = require("../models/Ride");
const Driver = require("../models/Driver");
exports.requestRide = async (req, res, next) => {
try {
const { pickup, drop } = req.body;
const ride = await Ride.create({ rider: req.user.id, pickup, drop });
res.status(201).json(ride);
} catch (err) {
next(err);
}
};
exports.assignDriver = async (req, res, next) => {
try {
const { rideId, driverId } = req.body;
const ride = await Ride.findById(rideId);
const driver = await Driver.findById(driverId);
if (!ride || !driver) return res.status(404).json({ message: "Ride/Driver not found" });
ride.driver = driver._id;
ride.status = "Accepted";
await ride.save();
res.json(ride);
} catch (err) {
next(err);
}
};
exports.updateRideStatus = async (req, res, next) => {
try {
const { rideId, status } = req.body;
const ride = await Ride.findById(rideId);
if (!ride) return res.status(404).json({ message: "Ride not found" });
ride.status = status;
if (status === "Completed") {
// Dummy fare calculation
ride.fare = Math.floor(Math.random() * 200) + 50;
}
await ride.save();
res.json(ride);
} catch (err) {
next(err);
}
};
🔐 src/middleware/authMiddleware.js
const jwt = require("jsonwebtoken");
exports.authMiddleware = (req, res, next) => {
const token = req.headers["authorization"];
if (!token) return res.status(401).json({ message: "No token provided" });
try {
const decoded = jwt.verify(token.split(" ")[1], process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
return res.status(401).json({ message: "Invalid token" });
}
};
🚦 Routes
src/routes/authRoutes.js
const express = require("express");
const { register, login } = require("../controllers/authController");
const router = express.Router();
router.post("/register", register);
router.post("/login", login);
module.exports = router;
src/routes/rideRoutes.js
const express = require("express");
const { requestRide, assignDriver, updateRideStatus } = require("../controllers/rideController");
const { authMiddleware } = require("../middleware/authMiddleware");
const router = express.Router();
router.post("/request", authMiddleware, requestRide);
router.post("/assign", authMiddleware, assignDriver);
router.post("/status", authMiddleware, updateRideStatus);
module.exports = router;
🌍 src/app.js
const express = require("express");
const dotenv = require("dotenv");
const helmet = require("helmet");
const morgan = require("morgan");
const authRoutes = require("./routes/authRoutes");
const rideRoutes = require("./routes/rideRoutes");
const { errorHandler } = require("./middleware/errorMiddleware");
dotenv.config();
const app = express();
app.use(express.json());
app.use(helmet());
app.use(morgan("dev"));
app.use("/api/auth", authRoutes);
app.use("/api/rides", rideRoutes);
app.use(errorHandler);
module.exports = app;
🖥️ src/server.js
const app = require("./app");
const connectDB = require("./config/db");
const PORT = process.env.PORT || 5000;
connectDB();
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
🔑 .env
PORT=5000
MONGO_URI=mongodb://localhost:27017/taxiapp
JWT_SECRET=supersecretkey
✅ Features Covered
-
User Auth (Rider/Driver/Admin with JWT).
-
Ride Requests (pickup & drop points stored).
-
Driver Assignment (admin/logic assigns driver).
-
Ride Status Flow (Requested → Accepted → Ongoing → Completed).
-
Fare Calculation (dummy logic, can expand with distance/time APIs).
-
Role-based Access (drivers & riders have different roles).
-
Real-Time Ready (can extend with Socket.io for live ride updates).
⚡ Extra Challenge (if time left in exam):
-
Integrate Google Maps API for distance & fare calculation.
-
Use Socket.io for live driver location updates.
-
Add payment gateway integration (Stripe/PayPal).
Would you like me to prepare a 3-hour exam roadmap for this Taxi App (step-by-step order: setup → auth → rides → drivers → extras) so you can simulate the real test?