When building API endpoints with Express, make request lifecycle control-flow and response semantics explicit and consistent:

Example:

const express = require('express');
const app = express();

// Global middleware (runs in order)
app.use((req, res, next) => {
  console.log(req.method, req.url);
  next(); // continue the lifecycle
});

const api = express.Router();
api.use('/v1', (req, res, next) => {
  // router-level middleware
  next();
});

api.get('/v1/resource', (req, res) => {
  // terminal handler: choose status code + body that match the outcome
  return res.status(200).json({ ok: true });
});

api.post('/v1/resource', express.json(), (req, res) => {
  if (!req.body || !req.body.name) {
    return res.status(400).send('Bad Request');
  }
  return res.status(201).json({ created: true });
});

app.use(api);
app.listen(3000);

Use this checklist in reviews: 1) Does every middleware either call next() or send a response (intentionally terminating)? 2) Are middleware/routers mounted in the intended order/module boundaries? 3) Do your route handlers return status codes and response bodies that accurately represent success/client error/server error?