- first of all clone this project from github. Then go to project path and install npm package.
git clone
cd bike-rental-reservation-system-backend
npm install
- Next, You will need to setup .env file where you have to setup this process config file:
NODE_ENV=development
PORT=5000
DATABASE_URL=database url
BCRYPT_SALT_ROUNDS=10
DEFAULT_PASS=usingYourPassword
JWT_ACCESS_SECRET=yourSecretKey
JWT_REFRESH_SECRET=yourSecretKey
JWT_ACCESS_EXPIRES_IN=1d
JWT_REFRESH_EXPIRES_IN=365d
- To Start this project. you have run npm command:
npm run start:dev
-
Live Deployment Link (Server): https://bike-rental-reservation-system-server-seven.vercel.app
-
GitHub Repository Links (Server): https://github.com/mdshohed/bike-rental-reservation-system-backend
-
Project Overview Video: https://youtu.be/RgKtffKd73Y
This a bike rental system where users could easily rent bikes online. User would be able to handle user registrations, bike availability, and booking management efficiently.
Models:
- User Model
- Bike Model
- Booking Model
- Programming Language: TypeScript
- Web Framework: Express.js
- ODM & Validation Library: Zod, Mongoose for MongoDB
- User Model:
- name: The name of the user.
- email: The contact email address.
- password: The account password.
- phone: The contact phone number.
- address: The physical address.
- role: admin / user
- Bike Model:
- name: The name of the bike model.
- description: A brief description of the bike.
- pricePerHour: The rental price per hour.
- isAvailable: Indicates if the bike is available for rental (default: true).
- cc: The engine capacity of the bike in cubic centimeters.
- year: The manufacturing year of the bike.
- model: The model of the bike.
- brand: The brand of the bike.
- Booking Model:
- userId: Reference to the User model.
- bikeId: Reference to the Bike model.
- startTime: The start time of the rental.
- returnTime: The return time of the rental.
- totalCost: The total cost of the rental.
- isReturned: Indicates if the bike has been returned (default: false).
-
Sign Up
-
Route: /api/auth/signup (POST)
-
Request Body:
{ "name": "John Doe", "email": "[email protected]", "password": "password123", "phone": "1234567890", "address": "123 Main St, Anytown", "role" : "admin" }
-
Response:
{ "success": true, "statusCode": 201, "message": "User registered successfully", "data": { "_id": "60d9c4e4f3b4b544b8b8d1f5", "name": "John Doe", "email": "[email protected]", "phone": "1234567890", "address": "123 Main St, Anytown", "role" : "admin", "createdAt": "2024-06-10T13:26:51.289Z", "updatedAt": "2024-06-10T13:26:51.289Z", "__v": 0 } }
-
-
User Login
-
Route: /api/auth/login (POST)
-
Request Body:
{ "email": "[email protected]", "password": "password123" }
-
Response:
{ "success": true, "statusCode": 200, "message": "User logged in successfully", "token": "jwt_token", "data": { "_id": "60d9c4e4f3b4b544b8b8d1c3", "name": "John Doe", "email": "[email protected]", "phone": "1234567890", "address": "123 Main St, Anytown", "role" : "admin" } }
-
-
Get Profile
-
Route: /api/users/me (GET)
-
Request Headers: Authorization: Bearer jwt_token
-
Response:
{ "success": true, "statusCode": 200, "message": "User profile retrieved successfully", "data": { "_id": "6666ff917181b8e5ffe04f91", "name": "admin", "email": "[email protected]", "phone": "1234567890", "address": "123 Main St, Anytown", "role": "admin", "createdAt": "2024-06-10T13:28:49.260Z", "updatedAt": "2024-06-10T13:28:49.260Z", "__v": 0 } }
-
-
Update Profile
-
Route: /api/users/me (PUT)
-
Request Headers: Authorization: Bearer jwt_token
-
Request Body:
{ "name": "John Updated", "phone": "0987654321" }
-
Response:
{ "success": true, "statusCode": 200, "message": "Profile updated successfully", "data": { "_id": "60d9c4e4f3b4b544b8b8d1c5", "name": "John Updated", "email": "[email protected]", "phone": "0987654321", "address": "123 Main St, Anytown", "role" : "admin" } }
-
-
Create Bike (Admin Only)
-
Route: /api/bikes (POST)
-
Request Headers: Authorization: Bearer jwt_token
-
Request Body:
{ "name": "Mountain Bike", "description": "A durable mountain bike for rough terrains.", "pricePerHour": 15, "cc": 250, "year": 2022, "model": "X1", "brand": "Yamaha" }
-
Response:
{ "success": true, "statusCode": 200, "message": "Bike added successfully", "data": { "_id": "60d9c4e4f3b4b544b8b8d1c4", "name": "Mountain Bike", "description": "A durable mountain bike for rough terrains.", "pricePerHour": 15, "isAvailable": true, "cc": 250, "year": 2022, "model": "X1", "brand": "Yamaha" } }
-
-
Get All Bikes
-
Route: /api/bikes (GET)
-
Response:
{ "success": true, "statusCode": 200, "message": "Bikes retrieved successfully", "data": [ { "_id": "bike_id", "name": "Mountain Bike", "description": "A durable mountain bike for rough terrains.", "pricePerHour": 15, "isAvailable": true, "cc": 250, "year": 2022, "model": "X1", "brand": "Yamaha" }, ...other bikes... ] }
-
-
Update Bike (Admin Only)
-
Route: /api/bikes/:id (PUT)
-
Request Headers: Authorization: Bearer jwt_token
-
Request Body:
{ "pricePerHour": 20 }
-
Response:
{ "success": true, "statusCode": 200, "message": "Bike updated successfully", "data": { "_id": "bike_id", "name": "Mountain Bike", "description": "A durable mountain bike for rough terrains.", "pricePerHour": 20, // Updated price per hour "isAvailable": true, "cc": 250, "year": 2022, "model": "X1", "brand": "Yamaha" } }
-
-
Delete Bike (Admin Only)
-
Route: /api/bikes/:id (DELETE)
-
Request Headers: Authorization: Bearer jwt_token
-
Response:
{ "success": true, "statusCode": 200, "message": "Bike deleted successfully", "data": { "_id": "bike_id", "name": "Mountain Bike", "description": "A durable mountain bike for rough terrains.", "pricePerHour": 20, "isAvailable": false, "cc": 250, "year": 2022, "model": "X1", "brand": "Yamaha" } }
-
-
Create Rental
-
Route: /api/rentals (POST)
-
Request Headers: Authorization: Bearer jwt_token
-
User information should be extracted from the token
-
Bike's availability status should be updated to false
-
Request Body:
{ "bikeId": "60d9c4e4f3b4b544b8b8d1c4", "startTime": "2024-06-10T09:00:00Z" }
-
Response:
{ "success": true, "statusCode": 200, "message": "Rental created successfully", "data": { "_id": "60d9c4e4f3b4b544b8b8d1c4", "userId": "60d9c4e4f3b4b544b8b8d1c3", "bikeId": "60d9c4e4f3b4b544b8b8d1c4", "startTime": "2024-06-10T09:00:00Z", "returnTime": null, "totalCost": 0, "isReturned": false } }
Important Note: Upon creating a rental, ensure the bike's isAvailable status is set to false to indicate that it is currently rented out and not available for other users to rent.
-
-
Return Bike (Admin Only)
-
Route: /api/rentals/:id/return (PUT)
-
Request Headers: Authorization: Bearer jwt_token
-
Request Body: Not needed
-
Bike's availability status should be updated to true
-
Hints: The cost should be calculated based on the start and return time of the rental. For example, if the start time is "2024-06-10T09:00:00Z" and the return time is "2024-06-10T18:00:00Z" (current time), the total rental duration is 9 hours. If the price per hour is $15, the total cost will be 9 * 15 = $135.
-
Response:
{ "success": true, "statusCode": 200, "message": "Bike returned successfully", "data": { "_id": "60d9c4e4f3b4b544b8b8d1c4", "userId": "60d9c4e4f3b4b544b8b8d1c3", "bikeId": "60d9c4e4f3b4b544b8b8d1c4", "startTime": "2024-06-10T09:00:00Z", "returnTime": "2024-06-10T18:00:00Z",// Current time when returning the bike "totalCost": 135, // Calculated based on rental duration "isReturned": true } }
-
-
Get All Rentals for User (My rentals)
-
Route: /api/rentals (GET)
-
Request Headers: Authorization: Bearer jwt_token
-
Response:
{ "success": true, "statusCode": 200, "message": "Rentals retrieved successfully", "data": [ { "_id": "60d9c4e4f3b4b544b8b8d1c4", "userId": "60d9c4e4f3b4b544b8b8d1c3", "bikeId": "60d9c4e4f3b4b544b8b8d1c4", "startTime": "2024-06-10T09:00:00Z", "returnTime": "2024-06-10T18:00:00Z", "totalCost": 135, "isReturned": true }, ...other rentals... ] }
-
-
No Data Found:
- When finding data, if the database collection is empty or does not match any data, return a generic message: "No data found."
-
Response:
{ "success": false, "message": "No Data Found", "data": [] }
-
- When finding data, if the database collection is empty or does not match any data, return a generic message: "No data found."
-
Error Handling:
- Implement proper error handling throughout the application. Use global error handling middleware to catch and handle errors, providing appropriate error responses error messages.
- Error Response Object should include the following properties:
-
success: false
-
message: Error Type (e.g., Validation Error, Cast Error, Duplicate Entry)
-
errorMessages:
[ { "path": "", "message": "Error message" } ]
-
Sample Error Response:
{ "success": false, "message": "E11000 duplicate key error collection:: email_1 dup key: { email: \\"[email protected]\\" }", "errorMessages": [ { "path": "", "message": "E11000 duplicate key error index: email_1 dup key: { email: \\"[email protected]\\" }" } ], "stack": "error stack" }
-
-
Not Found Route:
- Implement a global "Not Found" handler for unmatched routes. When a route is not found, respond with a generic message: "Not Found."
-
Response:
{ "success": false, "statusCode": 404, "message": "Not Found" }
-
- Implement a global "Not Found" handler for unmatched routes. When a route is not found, respond with a generic message: "Not Found."
Implement an Authentication Middleware to authenticate your application. Ensures that only user and admin can access their own accessible routes.
{
"success": false,
"statusCode": 401,
"message": "You have no access to this route",
}
- dotenv
- cors(dependencies/devDependencies)
- express(dependencies/devDependencies)
- mongoose
- cookie-parser(dependencies/devDependencies)
- Zod
- eslint
- prettier
- http-status
- jsonwebtoken(dependencies/devDependencies)
- bcrypt(dependencies/devDependencies)