REST API Masterclass
Architecting Modern Backends01.Home02.What is REST?03.HTTP Deep Dive04.URI Best Practices05.JSON & Data Formats06.Environment Setup07.Your First Resource08.Advanced Controllers09.Database Strategy10.JWT Authentication11.Role-Based Auth (RBAC)12.API Versioning13.Filtering & Searching14.Pagination & Sorting15.Global Error Handling16.Rate Limiting17.CORS & Security18.Swagger & OpenAPI19.Testing with Supertest20.Webhooks & Caching21.Production Checklist
Advanced Controllers & Logic
As your API grows, putting logic directly inside route files becomes a nightmare. Master the art of Decoupling.
1. The Route vs The Controller
The route file should only define where requests go. The controller handles what happens.
// routes/userRoutes.js
router.get('/:id', userController.getUser);
// controllers/userController.js
exports.getUser = async (req, res, next) => {
const user = await UserService.findById(req.params.id);
res.json({ data: { user } });
};2. Higher-Order Controllers
For standard CRUD, don't repeat yourself. Use a generic handler factory.
const deleteOne = (Model) => async (req, res) => {
await Model.findByIdAndDelete(req.params.id);
res.status(204).json({ data: null });
};
// Usage
exports.deleteUser = deleteOne(User);
exports.deleteProduct = deleteOne(Product);3. Business Logic vs DB Logic
Don't put complex business rules in your controllers. Move them to aService Layer. This makes your API logic testable without a database.
Scalability Tip: By keeping your controllers "thin" (only handling input and output), you can switch from one framework (e.g., Express) to another (e.g., Fastify) with minimal changes to your core logic.