Exercise 2: Why Express Still Counts as a Framework — Possible Solution ==================================================================== TJ HOLOWAYCHUK'S OWN REAL, QUOTED REASON ------------------------------ Node.js itself, in his own words, "lacked key features like routing, templating, middleware, and robust error handling." Express was built specifically to provide these - but as the chapter notes, Express only ships genuinely robust routing and middleware as standard; templating and data access are both left as deliberate, pluggable integration points rather than being provided outright. WHY "NO BUILT-IN ORM/TEMPLATE ENGINE" DOESN'T DISQUALIFY IT ------------------------------ The library-vs-framework test from earlier in this chapter is "who calls whom" - not "how many features does it ship." Express still passes that test cleanly for the two capabilities it does provide: const app = require('express')(); app.get('/users/:id', (req, res) => { res.send(`User ${req.params.id}`); }); app.listen(3000); The arrow function passed to app.get() is never called directly by any application code anywhere. Express's own internal routing machinery is what calls it - and only once a real incoming request matches the GET /users/:id pattern, with req itself constructed and handed to the function by Express, not by the developer. Control flow for routing is genuinely inverted here, exactly the same real mechanism as the Django view function example - regardless of the fact that Express has no opinion at all about how the resulting data eventually becomes a database record or an HTML page. THE REAL DISTINCTION: SCOPE, NOT MECHANISM ------------------------------ A framework's genuine framework-ness is decided per-capability, by whether inversion of control actually applies to that capability - not by counting how many total capabilities a framework happens to bundle. Express fully inverts control for routing and middleware (the two capabilities it ships), which is enough to make it a genuine framework for those two things. It simply chooses not to extend that same inversion to templating or data access, leaving those as ordinary libraries (Sequelize, Prisma, EJS) that application code calls directly, on its own schedule, in the traditional library sense. WHY THIS WORKS AS AN ANSWER ------------------------------ It applies the chapter's own precise "who calls whom" test directly to a real Express route handler rather than just asserting Express counts as a framework, and explains specifically why bundling fewer of the four capabilities doesn't change whether inversion of control genuinely applies to the ones it does provide - the real, scope-independent property the test is actually checking for.