Advanced Backend Coding Questions - Web Programming Final Exam
Q1. Build a RESTful API Endpoint with Validation
Route: POST /api/transactions
- Validates required fields: date, expenseType, description, amount
- Returns 400 if validation fails, 201 if successful
Code:
app.post('/api/transactions', async (req, res) => {
const { date, expenseType, description, amount } = req.body;
if (!date || !expenseType || !description || !amount) {
return res.status(400).json({ error: 'All fields are required' });
}
try {
const newTransaction = await Transaction.create(req.body);
res.status(201).json(newTransaction);
} catch (err) {
res.status(500).json({ error: 'Server error', details: err.message });
}
})
Q2. Handle Non-Existent Resources Gracefully
Route: GET /transactions/:id
- Returns 404 if no transaction is found, or 400 if ID is invalid
Code:
app.get('/transactions/:id', async (req, res) => {
try {
const txn = await Transaction.findById(req.params.id);
if (!txn) return res.status(404).send('Transaction not found');
res.render('transactionDetails', { txn });
} catch (err) {
res.status(400).send('Invalid ID');
}
})
Q3. Global Error Handling Middleware
Error Middleware:
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ status: 'error', message: err.message || 'Unexpected server error' });
});
Usage:
app.get('/fail', (req, res) => {
throw new Error('Manual crash');
});
Q4. Custom Mongoose Validation Errors
Model Schema:
amount: {
type: Number,
required: true,
validate: {
validator: value => value > 0,
message: 'Amount must be greater than zero.'
}
}
API Integration:
if (err.name === 'ValidationError') {
return res.status(400).json({ error: err.message });
}
Q5. Add Filtering Query Parameters to API
Route: GET /api/transactions?expenseType=Food
Code:
app.get('/api/transactions', async (req, res) => {
try {
const filter = {};
if (req.query.expenseType) {
filter.expenseType = req.query.expenseType;
}
const txns = await Transaction.find(filter);
res.json(txns);
} catch (err) {
res.status(500).json({ error: 'Server error' });
}
});
Q6. Toggle Status with PATCH
Route: PATCH /transactions/:id/toggle-status
Code:
app.patch('/transactions/:id/toggle-status', async (req, res) => {
try {
const txn = await Transaction.findById(req.params.id);
if (!txn) return res.status(404).send('Transaction not found');
txn.status = !txn.status;
await txn.save();
res.json(txn);
} catch (err) {
res.status(400).send('Invalid ID');
}
});
Q7. Delete with Confirmation Response
Route: DELETE /api/transactions/:id
Code:
app.delete('/api/transactions/:id', async (req, res) => {
try {
const txn = await Transaction.findByIdAndDelete(req.params.id);
if (!txn) return res.status(404).json({ error: 'Transaction not found' });
res.json({ message: 'Transaction successfully deleted', txn });
} catch (err) {
res.status(400).json({ error: 'Invalid ID format' });
}
});