Project Layout for an API

Express 24,430 imposes no structure, so you impose one. This is the layout the chapter uses, conventional enough that a new developer finds their way around in minutes.

The Bookshelf project layoutJavaScript
bookshelf/src/
  app.js            createApp(): builds the app, returns it, never listens
  server.js         reads config, calls app.listen()
  config.js         environment variables parsed and validated once
  routes/           one router per resource: books.js, authors.js
  controllers/      request in, response out; no business rules
  services/         business rules; knows nothing about req or res
  data/             the store interface and its in-memory implementation
  middleware/       auth.js, validate.js, error-handler.js

The rule that matters is the split between app.js and server.js. createApp() assembles middleware and routers and returns the app without binding a port; server.js is the only file that calls listen. That lets the test suite build a fresh app per file for Supertest 14,405 (HTTP Testing with Supertest) without racing for port 3000, and lets a serverless platform import the app directly.

The layers under it are a gradient, not a law. routes/ maps URLs to handlers, controllers/ translates between HTTP and plain arguments, services/ holds the rules you would keep if you replaced HTTP with a message queue, and data/ alone knows how records are stored. A small project can fold controllers into routes, but not data/: MongoDB replaces it wholesale. Make config.js throw on startup when a required variable is missing, too — a server that refuses to boot without JWT_SECRET beats one that signs every token with undefined.