How to separate concerns across layers — Intermediate
Routers wire URLs, controllers handle HTTP, services own data—avoid SQL or business rules in route files.
Learn: Layers exist so each file has one reason to change. If SQL appears in a router, move it to a service. If HTTP status logic sprawls across services, return errors and map them in the controller.
Supplementary examples
Controller maps service error to 404
try {
const row = await service.read(id);
res.json({ data: row });
} catch (err) {
next(err); // errorHandler reads err.status
}Course example
// Good: router only connects URL to controller
router.route("/").get(controller.list).post(controller.create);
// Avoid: database logic inline in router
// router.get("/", async (req, res) => {
// const rows = await knex("users").select(); // move to service
// });
Additional references & examples
- Thinkful — Organizing Express (pastes example)
Router/controller structure demonstration project.
- Express.js guide
Routing, middleware order, and request/response lifecycle.