Discover how to build a powerful vehicle rentals backend using Lovable. Follow our step-by-step guide covering planning, coding, and deployment for an efficient rental system.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Setting Up Your Lovable Project
index.js
).
Adding Dependencies via Code
lovable.config.js
in your project’s root folder.
module.exports = {
dependencies: {
"express": "latest", // Web framework for API endpoints
"mongoose": "latest", // ODM for MongoDB connection
"body-parser": "latest" // Middleware to handle JSON request bodies
}
};
Creating Database Models for Vehicles and Rentals
models.js
in your project’s root directory.
const mongoose = require('mongoose');
const vehicleSchema = new mongoose.Schema({
make: { type: String, required: true },
model: { type: String, required: true },
year: Number,
available: { type: Boolean, default: true }
});
const rentalSchema = new mongoose.Schema({
vehicle: { type: mongoose.Schema.Types.ObjectId, ref: 'Vehicle' },
renterName: { type: String, required: true },
rentalDate: { type: Date, default: Date.now },
returnDate: Date
});
module.exports = {
Vehicle: mongoose.model('Vehicle', vehicleSchema),
Rental: mongoose.model('Rental', rentalSchema)
};
Building API Endpoints for Vehicle Rentals
routes.js
to define your API endpoints.
const express = require('express');
const router = express.Router();
const { Vehicle, Rental } = require('./models');
// Retrieve all vehicles
router.get('/vehicles', async (req, res) => {
try {
const vehicles = await Vehicle.find();
res.json(vehicles);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Add a new vehicle
router.post('/vehicles', async (req, res) => {
try {
const vehicle = new Vehicle(req.body);
await vehicle.save();
res.status(201).json(vehicle);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// Create a new rental
router.post('/rentals', async (req, res) => {
try {
const rental = new Rental(req.body);
await rental.save();
res.status(201).json(rental);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// Return a vehicle by updating the rental record
router.put('/rentals/:id/return', async (req, res) => {
try {
const rental = await Rental.findByIdAndUpdate(req.params.id, { returnDate: new Date() }, { new: true });
res.json(rental);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
module.exports = router;
Setting Up the Server Entry Point
index.js
) to configure the Express server.
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const routes = require('./routes');
const app = express();
// Use body-parser middleware to parse JSON request bodies
app.use(bodyParser.json());
// Link API routes under the /api endpoint
app.use('/api', routes);
// Connect to MongoDB (adjust the connection string as needed)
mongoose.connect('mongodb://localhost:27017/vehiclerentals', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log('Connected to database');
}).catch(err => {
console.error('Database connection error:', err);
});
// Start the server on port 3000
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Testing Your Backend on Lovable
index.js
as the entry point.
Deploying and Sharing Your Backend
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
// In-memory database mocks
let rentals = [];
let nextRentalId = 1;
// POST /rentals - Create a new rental booking
app.post('/rentals', (req, res) => {
const { vehicleId, userId, startDate, endDate } = req.body;
if (!vehicleId || !userId || !startDate || !endDate) {
return res.status(400).json({ error: 'Missing required fields' });
}
// Convert dates to Date objects
const start = new Date(startDate);
const end = new Date(endDate);
if (end <= start) {
return res.status(400).json({ error: 'End date must be after start date' });
}
// Check overlapping bookings for the same vehicle
const conflict = rentals.find(rental => rental.vehicleId === vehicleId &&
((start < new Date(rental.endDate)) && (end > new Date(rental.startDate)))
);
if (conflict) {
return res.status(409).json({ error: 'Vehicle already booked in the selected period' });
}
// Create and store the rental
const newRental = {
id: nextRentalId++,
vehicleId,
userId,
startDate: start,
endDate: end,
status: 'booked'
};
rentals.push(newRental);
res.status(201).json(newRental);
});
// GET /rentals/:id - Retrieve details of a specific rental
app.get('/rentals/:id', (req, res) => {
const rental = rentals.find(r => r.id === parseInt(req.params.id, 10));
if (!rental) {
return res.status(404).json({ error: 'Rental not found' });
}
res.json(rental);
});
// GET /vehicles/availability - Check vehicle availability between two dates
app.get('/vehicles/availability', (req, res) => {
const { startDate, endDate } = req.query;
if (!startDate || !endDate) {
return res.status(400).json({ error: 'startDate and endDate query parameters are required' });
}
const start = new Date(startDate);
const end = new Date(endDate);
if (end <= start) {
return res.status(400).json({ error: 'End date must be after start date' });
}
// Hypothetical full list of vehicles
const vehicles = [
{ id: 1, model: 'Sedan', make: 'Toyota' },
{ id: 2, model: 'SUV', make: 'Honda' },
{ id: 3, model: 'Truck', make: 'Ford' }
];
// Structure the response to reflect availability using Lovable strategy for data transformation
const availability = vehicles.map(vehicle => {
const isBooked = rentals.some(rental => rental.vehicleId === vehicle.id &&
((start < new Date(rental.endDate)) && (end > new Date(rental.startDate)))
);
return {
vehicleId: vehicle.id,
make: vehicle.make,
model: vehicle.model,
available: !isBooked
};
});
res.json(availability);
});
app.listen(3000, () => {
console.log('Vehicle Rentals Backend running on port 3000');
});
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
// In-memory rentals database example
let rentals = [
// Example entry: { id: 1, vehicleId: 101, city: 'New York', basePrice: 100 }
];
// Fetch dynamic pricing multiplier from an external API based on city name
async function getDynamicPricingMultiplier(city) {
try {
const response = await axios.get('https://api.externalpricing.com/multiplier', {
params: { city }
});
// Assuming the API response is a JSON with property "multiplier"
return response.data.multiplier;
} catch (error) {
// Fallback to default multiplier if external API is unavailable
return 1.0;
}
}
// GET endpoint to calculate the final rental price for a given rental id
app.get('/rentals/:id/final-price', async (req, res) => {
const rentalId = parseInt(req.params.id, 10);
const rental = rentals.find(r => r.id === rentalId);
if (!rental) {
return res.status(404).json({ error: 'Rental not found' });
}
const multiplier = await getDynamicPricingMultiplier(rental.city);
const finalPrice = rental.basePrice \* multiplier;
res.json({
rentalId: rental.id,
vehicleId: rental.vehicleId,
city: rental.city,
basePrice: rental.basePrice,
multiplier,
finalPrice
});
});
// POST endpoint to create a new rental record
app.post('/rentals', (req, res) => {
const { vehicleId, city, basePrice } = req.body;
if (!vehicleId || !city || !basePrice) {
return res.status(400).json({ error: 'Missing required fields: vehicleId, city, basePrice' });
}
const newRental = {
id: rentals.length + 1,
vehicleId,
city,
basePrice
};
rentals.push(newRental);
res.status(201).json(newRental);
});
app.listen(3000, () => {
console.log('Vehicle Rentals Backend running on port 3000');
});
const express = require('express');
const app = express();
app.use(express.json());
let rentals = [
{ id: 1, vehicleId: 101, startDate: "2023-10-15T10:00:00Z", endDate: "2023-10-20T10:00:00Z" },
{ id: 2, vehicleId: 101, startDate: "2023-10-22T10:00:00Z", endDate: "2023-10-25T10:00:00Z" }
];
app.put('/rentals/:id/extend', (req, res) => {
const rentalId = parseInt(req.params.id, 10);
const { newEndDate } = req.body;
if (!newEndDate) {
return res.status(400).json({ error: "newEndDate is required" });
}
const rental = rentals.find(r => r.id === rentalId);
if (!rental) {
return res.status(404).json({ error: "Rental not found" });
}
const currentEnd = new Date(rental.endDate);
const proposedEnd = new Date(newEndDate);
if (proposedEnd <= currentEnd) {
return res.status(400).json({ error: "New end date must be after the current end date" });
}
const overlappingRental = rentals.find(r =>
r.vehicleId === rental.vehicleId &&
r.id !== rentalId &&
new Date(r.startDate) < proposedEnd &&
new Date(r.startDate) >= currentEnd
);
if (overlappingRental) {
return res.status(409).json({ error: "Extension conflicts with an upcoming booking" });
}
rental.endDate = proposedEnd.toISOString();
res.json(rental);
});
app.listen(3000, () => console.log('Vehicle Rentals Backend on port 3000'));
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Understanding Vehicle Rentals Backend Requirements
Selecting Appropriate AI Code Generators and Tools
Designing the System Architecture
Setting Up the Development Environment
Building the Backend Using AI Code Generators
from sqlalchemy import create\_engine
from sqlalchemy.orm import sessionmaker
DATABASE\_URL = "postgresql://username:password@localhost/vehiclerentals"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
from flask import Flask, request, jsonify
app = Flask(**name**)
@app.route('/vehicles', methods=['GET'])
def get\_vehicles():
# AI-generated code might include database query logic here
vehicles = [] # Replace with actual DB call
return jsonify(vehicles)
@app.route('/vehicles', methods=['POST'])
def add\_vehicle():
data = request.get\_json()
# Process and validate data here
return jsonify({"message": "Vehicle added successfully"}), 201
Implementing Security Best Practices
Testing the Application
def test_get_vehicles(client):
response = client.get('/vehicles')
assert response.status\_code == 200
# Verify the structure of the returned data
Deploying and Monitoring the Backend
Maintenance and Future Enhancements
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.