# Application Structure

Course: [Express.js](https://www.devtutorials.ai/learn/expressjs) · Section: Architecture and Reference
Source: https://www.devtutorials.ai/learn/expressjs/architecture-reference/application-structure

> Splitting app.js and server.js, a project folder layout, a central config module, registration order, startup errors and graceful shutdown, testing with node:test and Supertest, Express Generator, and keeping code healthy.

## Application Structure Introduction

Small demos fit in one file. Real apps do not.

- **Application structure** = how you split an app into files and folders.
- Good structure makes code easy to find, change and test.
- Express does not force a layout. You choose one and keep it consistent.
- This lesson shows a common, simple layout for the canteen API.
- It also shows the order to register everything, and how to test it.

**Simple lesson:** Put each kind of code in its own place, and register it in a fixed order.

### A Real-World Example

Think about a well-run school kitchen.

1. Vegetables, spices and plates each have their own shelf.
2. Every cook knows where to find things, even on their first day.
3. The work happens in a fixed order: wash, cut, cook, serve.
4. A food inspector can check each station on its own.

Shelves are folders. The fixed order is the registration order. The inspector is your tests.

In this lesson, you will learn:

1. Why to split `app.js` and `server.js`.
2. A folder layout for a real Express project.
3. A central configuration module.
4. The order to register settings, middleware, routes and errors.
5. How to start and stop the server safely.
6. How to test routes with Supertest.

## Project Layout

```text
canteen-api/
├── src/
│   ├── app.js             builds and exports the Express app
│   ├── server.js          starts the HTTP server
│   ├── config/index.js    reads and checks settings
│   ├── routes/            one router per resource
│   ├── handlers/          the functions routes call
│   ├── middleware/        logger, auth, validation, errors
│   ├── utils/             small shared helpers
│   └── views/             templates, if the app renders pages
├── public/                static files
├── test/                  automated tests
├── .env  .env.example  .gitignore
└── package.json
```

- **src/** = all the code that runs, kept apart from settings and tests.
- **routes/** = which URL goes where. **handlers/** = what happens there.
- **middleware/** = shared steps, such as checks and logging.
- **config/** = the only place that reads `process.env`.
- **utils/** = small helpers, such as `formatPrice`.
- **public/** and **views/** = files for browsers. See **Views and Static Files**.

**Simple lesson:** Routes, handlers, middleware and config each get their own folder.

## app.js and server.js

- **app.js** creates the app, registers everything and **exports** it. It never calls `listen`.
- **server.js** imports the app, reads the port and calls `listen`.
- Tests import `app.js` and call it directly, with no real port.
- You can start the same app in different ways, such as with HTTPS or in a cloud function.
- This split was introduced in **Introduction to Express.js**. Here it carries a whole project.

- Open the explorer to see the whole tree.
- Each file is short, and its job is clear from its folder and name.

**Simple lesson:** app.js wires everything up. server.js only starts it.

## Central Configuration

- **One config module** reads `process.env` and checks it.
- Every other file imports `config`, never `process.env` directly.
- Convert types once: `Number(process.env.PORT ?? 3000)`.
- Fail at startup when a required value is missing.
- Changing a setting name later means changing one file.

**Simple lesson:** One file reads the environment. Everyone else reads `config`.

## Registration Order

The order of `app.use` and `app.set` calls decides how every request flows.

1. **Settings:** `trust proxy`, `x-powered-by`, view engine.
2. **Security:** `helmet()`, `cors()`, rate limits.
3. **Logging:** request logger or Morgan.
4. **Parsers:** `express.json()`, `express.urlencoded()`, then cookies and sessions.
5. **Static files:** `express.static()`.
6. **Authentication:** middleware that sets `req.user`.
7. **Routers:** your routes.
8. **Not found:** the 404 handler.
9. **Errors:** the four-input error handler, always last.

Easy way to remember: **settings, shields, logs, parsers, files, users, routes, 404, errors.**

- Compare **Headers**: `/menu` has no security headers, `/later` has them.
- Move `app.use(helmet())` to the top, and both routes are protected.

Order bugs give no error message. The app works, just less safely. Review the registration order in every code review.

**Simple lesson:** Middleware only helps what comes after it, so order is everything.

## Starting and Stopping the Server

- **Read the port** from `config`.
- **Handle startup errors:** in Express 5, the `listen` callback gets the error, such as a busy port.
- **Log one clear line** when the server is ready.
- **Graceful shutdown** = finish current requests before stopping.
- Hosts send **SIGTERM** before stopping a server. Listen for it, call `server.close()`, then exit.

```js
const server = app.listen(config.port, () => console.log("Ready"));

process.on("SIGTERM", () => {
  console.log("SIGTERM received, closing the server");
  server.close(() => {
    // Close database connections here.
    process.exit(0);
  });
});
```

In this lab, the Stop button ends the server at once, like Ctrl + C. On a real host, the SIGTERM code above lets requests in progress finish first.

- Instead of a long stack trace, the terminal shows one helpful line.
- `process.exit(1)` tells the host the start failed, so it can alert you or retry.

**Simple lesson:** Start with clear errors, and stop gently so no request is cut off.

## Testing Routes with Supertest

**Automated test** = code that checks your code, run with one command.

- **node:test** = Node.js's built-in test runner. Run it with `node --test`.
- **node:assert/strict** = checks such as `assert.equal(a, b)`.
- **Supertest** = sends requests straight to your `app`, with no real port. Install: `npm install --save-dev supertest`.
- `await request(app).get("/api/menu").expect(200)` checks one route.
- Test files usually end in `.test.js` and live in `test/`.

- Press **▶ Run**. The terminal runs `node --test` and shows each test.
- Change `"Idli"` in the test to `"Dosa"` and run again. One test fails and says why.
- Tests import `app.js`, which is why it must not call `listen`.

- The test fails with `expected 201 "Created", got 200 "OK"`.
- Change `status(200)` to `status(201)` in `app.js`, and the test passes.

**Simple lesson:** Export the app, test it with Supertest, and run `node --test` before every change.

## Express Generator

**express-generator** = an official tool that creates a starter project.

```bash
npx express-generator --view=ejs canteen-site
```

- It creates `app.js`, `bin/www` (the server), `routes/`, `views/` and `public/`.
- `--view` picks the template engine, such as `ejs` or `pug`.
- It uses older CommonJS style (`require`), not `import`.
- It is quick for server-rendered sites, but you will change most files.
- Building the structure by hand, as in this lesson, teaches you every part.

**Simple lesson:** The generator gives a fast start. A hand-made layout gives you full control.

## Keeping the Code Healthy

- **Small route files:** if a file passes about 200 lines, split it.
- **Reuse handlers and middleware** instead of copying code.
- **Consistent names:** `routes/menu.js`, `handlers/menu.js`, `middleware/auth.js`.
- **One-way imports:** routes import handlers, handlers import utils. Never the other way.
- **Circular imports** = two files that import each other. Values may be `undefined` at startup. Move shared code to a third file.

**Simple lesson:** Small files, clear names and one-way imports keep a project easy to grow.

## Common mistakes

<div className="tscroll">

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `app.listen` inside app.js | One file is simpler | app.js exports, server.js listens | Tests start real servers and clash |
| `process.env` in every file | It is always available | Read it once in config | Typos and missing checks everywhere |
| 404 handler before routes | Order does not matter | Routes, then 404, then errors | Every request gets 404 |
| No SIGTERM handling | Stopping is instant anyway | Close the server gently | Users see cut-off requests during deploys |
| Business logic in route files | Routes can do everything | Routes point, handlers work | Huge files that are hard to test |
| Two modules importing each other | Imports always work | Avoid cycles | `undefined` values at startup |
| No tests | Manual checks are enough | Automate with `node --test` | Old features break silently |

</div>

## Check Yourself

## Exercises

## What to Remember

- app.js builds and exports the app. server.js starts it.
- Folders: routes, handlers, middleware, config, utils, views, public, test.
- One config module reads and checks `process.env`.
- Register in order: settings, security, logging, parsers, static, auth, routes, 404, errors.
- Handle startup errors, and shut down gently on SIGTERM.
- Test routes with Supertest and `node --test`.

Next: **Express with TypeScript**. You will add types to your Express app and catch mistakes early.
