open atlas
↑ Back to track
Backend Architecture BE · 02 · 09

Middleware and DI: code and config reading

Read real Express and NestJS snippets — a middleware ordering bug, a singleton holding request state, a request-scope bubbling cost, and a dependency cycle — and pick the highest-leverage fix.

BE Senior ◷ 14 min
Level
FoundationsJuniorMiddleSenior

Middleware and DI bugs are diagnosed in wiring code and registration order, not in business logic. Read each snippet, predict what breaks under load, and choose the fix a senior engineer reaches for first.

Goal

Practise the loop every middleware/DI incident runs: read the pipeline order or the wiring, predict the failure (a leaked response, a cross-user data race, a per-request graph rebuild, an unresolvable cycle), and pick the structural fix over the band-aid.

Snippet 1 — the middleware order

const app = express();

app.use(expensiveBodyParser());   // parses + buffers the full body
app.use(rateLimit({ max: 100 })); // rejects the 101st request
app.use(authenticate);            // verifies the bearer token
app.use('/api', apiRouter);
Quiz

A flood of unauthenticated, oversized requests drives CPU to 100%. What is wrong with this ordering, and what is the fix?

Snippet 2 — the singleton field

@Injectable()                     // default scope: singleton
export class AuditService {
  private currentUser?: User;     // set per request, read later

  setUser(u: User) { this.currentUser = u; }

  record(action: string) {
    log(`${this.currentUser?.id} did ${action}`);
  }
}
Quiz

Under concurrent load the audit log attributes actions to the wrong user. Why, and what is the cleanest fix?

Snippet 3 — the request-scoped logger

@Injectable({ scope: Scope.REQUEST })   // one instance per request
export class ContextLogger { /* holds the request id */ }

@Injectable()                            // intended as a singleton
export class PaymentService {
  constructor(private log: ContextLogger) {}   // injects request-scoped dep
}
// AppController injects PaymentService, OrderService injects PaymentService...
Quiz

After this change, a load test shows higher allocation and latency across many unrelated services. Why?

Snippet 4 — the dependency cycle

@Injectable()
export class AuthService {
  constructor(private users: UserService) {}   // needs UserService
}

@Injectable()
export class UserService {
  constructor(private auth: AuthService) {}     // needs AuthService
}
Quiz

The container throws 'cannot resolve dependencies'. What is the root cause, and the structurally correct fix?

Recap

Every middleware/DI incident is read in wiring, not logic. Middleware order is a cost and security lever — put cheap rejections (rate limit, auth) before expensive work like body parsing. A singleton must be stateless with respect to the request; storing per-request fields on it races across concurrent users, so pass the value as an argument. Request scope bubbles up the injection chain and rebuilds a subgraph per request, so reach for it only when truly needed. And a dependency cycle has no topological order — the structural fix is to extract a shared third class, not to silence the resolver with forwardRef.

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.