I have all the database calls directly inside /routes/*:
e.g.
//routes/users.ts
route.get("/id", (req, res) => {
res.send(db.findOne(id: req.sessions.id));
});
But someone said I should put the code inside /controllers/.
But I find that I just add an extraneous call with no benefit:
//routes/users.ts
route.get("/id", (req, res) => {
res.send(userController);
});
And inside /controllers/:
//controllers/userController.ts
export default function users() {
return db.findOne(id: req.sessions.id);
}
Is this approach somehow better?
Now the routes folder is just a thin shim to the controller. I see no benefit to the change.
The approach of splitting your app's logic into
/routes
and/controllers
is a matter of separation of concerns, the design pattern isn’t about immediate, tangible benefits in simple scenarios but rather about maintaining a clean architecture as your application grows in complexity.By separating the routing logic (which deals with HTTP and middleware) from the business logic (controllers) you make your code easier to maintain, If you need to change a database call you only need to update the controller, not the route.
Controllers are easier to test in isolation than routes that are tightly coupled with Express'
req
andres
objects.You can reuse controllers across different routes which is harder when the logic is embedded within the route definitions.
New devs that hop on your project in future scenarios can quickly understand the structure of your application if it follows this widely-adopted pattern.
I’ll try to explain it in code: ``` // routes/users.ts import express from 'express'; import userController from '../controllers/userController';
const router = express.Router();
// Route is only concerned with HTTP layer: parsing request and sending response router.get("/id", userController.getUserById);
export default router;
// controllers/userController.ts import { Request, Response } from 'express'; import db from '../db'; // hypothetical path to your database module
// Controller is only concerned with business logic export function getUserById(req: Request, res: Response) { const user = db.findOne({ id: req.sessions.id }); if (user) { res.send(user); } else { res.status(404).send('User not found'); } } ```
userController.getUserById
is a function that handles the business logic, and it's called by the route. The route doesn't know how the user is fetched; it just knows that it needs to call a function when the/id
endpoint is hit.While it might seem like an extra layer without much benefit at first, especially in smaller apps this pattern greatly enhances the scalability and maintainability of your application as it grows and It's a foundational principle of clean code architecture to separate different types of logic into their respective layers :)