awesome-everything RU
↑ Back to the climb

Backend Architecture

Middleware and DI: code and config reading

Crux 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.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 14 min

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.

Continue the climb ↑Middleware and DI: wire a testable service
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.