Chapter 36: Practical Case One: Building an API Gateway with Auth and Rate Limiting from Scratch
2026.08.3036.1 Breakdown and Blueprint Design
Scenario: Build the core logic of an API gateway with authentication (Auth) and rate-limiting (Rate Limit) mechanisms from scratch.
This scenario condenses the most classic methodology question in AI-assisted programming: placing these two cross-cutting concerns -- "authentication" and "rate limiting" -- in the correct architectural positions while keeping them decoupled. It is the best practice drillground for the "structural milestones" and "rebuild at first sign of chaos" discipline.
Phase One: Breakdown (systematic dimensionality reduction).
Following the "systematic dimensionality reduction" principle from Chapter 10, we build a dependency tree to clarify the absolute sequence of implementation:
Phase One (lay the foundation): JWT Auth Middleware (core, independent, do first)
Phase Two (build load-bearing walls): Rate-Limit Middleware (depends on Phase One infrastructure)
Phase Three (run utilities): Route Binding and Middleware Assembly (horizontal integration)
Key Decision: Phase One's milestone is only "complete the JWT Auth middleware" -- absolutely do not touch rate-limiting logic yet. Split the two cross-cutting concerns into two independent structural milestones, each verifiable on its own.
Blueprint Design Points (written into CONTEXT.md):
- Tech Stack Constraints: Node.js + Express (or equivalent framework); JWT parsing library; rate-limiting driver with reserved interface;
- Data Models: No database needed (middleware is pure logic), but must define Token payload structure (user_id, exp, iat) and the data contract for rate-limit counters;
- API Contracts: Middleware inputs (request object) and outputs (request object + authenticated user context / 429 response); custom exception formats (401 AppError, 429 RateLimitError);
- Milestone Dependency Tree: M1 JWT Auth Middleware → M2 Rate-Limit Middleware → M3 Gateway Route Assembly and Integration Acceptance.
Directional Tip: Before having the AI write any code, hand it the CONTEXT.md and acceptance criteria first. An example of the M1 acceptance criteria:
Acceptance Criteria (M1: JWT Auth Middleware):
1. Parse the Bearer Token in the Authorization header;
2. Verify signature and expiration time; return 401 if expired;
3. On success, inject user_id into the request context;
4. All failure cases uniformly throw a 401 AppError;
5. Sensitive fields in the Token payload (e.g., secret key) must not leak into logs.
36.2 Milestone Progression and Acceptance
Milestone M1: JWT Auth Middleware.
- Issue Instruction: Feed the acceptance criteria to the AI as hard constraints (acceptance-driven development);
- Coding: AI generates the middleware code;
- Acceptance: Functional test (test requests with valid/expired/forged tokens one by one), architectural test (does the middleware maintain single responsibility, does it sneak in unnecessary libraries?), security test (no hardcoded secrets, Token payload doesn't leak sensitive info);
- Conclusion: PASS →
git committo solidify → update CONTEXT.md (record M1 completion, confirm API contract) → clear session.
Milestone M2: Rate-Limit Middleware.
- Issue Instruction: Clarify technical constraint -- "the rate-limiting logic must remain as an independent middleware, never coupled with the auth middleware";
- Coding: AI generates the rate-limiting logic;
- Acceptance: Functional test (requests exceeding the threshold within a time window return 429), architectural test (still decoupled?), boundary test (concurrent scenarios, counter reset);
- Conclusion: PASS → commit → update blueprint.
Milestone M3: Route Assembly and Integration Acceptance.
- Mount both middlewares onto the gateway route in the correct order;
- Integration Acceptance: Authentication failure short-circuits before entering rate-limiting logic; rate-limit counting treats authenticated and unauthenticated requests consistently; end-to-end test of the full chain passes.
36.3 A Deliberate Architecture Drift: Identify → Elevate → Rebuild
Deliberately cause an architecture drift (this is the full version of the Chapter 10 practical drill):
How the drift occurs: Issue a deliberately vague instruction to the AI -- "add rate-limiting functionality" (without providing any technical constraints). The AI will very likely determine that "the simplest way to implement this": hardcode a memory-based rate-limiting logic directly into the current auth middleware file. Auth and rate-limiting become tightly coupled, and the file begins to bloat.
Identification Signals (danger radar alarm):
- Foundation tampering: The AI modified the already-solidified auth middleware file (M1, an already-accepted milestone);
- Size out of control: A single middleware file rapidly bloats.
Elevated Instruction (First Step Correction): Don't blame the details; point out the structural flaw in architect language:
"Your recent implementation hardcodes the rate-limiting logic inside the auth middleware, breaking the Single Responsibility Principle and coupling two cross-cutting concerns. Please extract the rate-limiting logic into a separate middleware to maintain module decoupling."
Stop Implementation (Second Step): If the AI falls into the "self-consistency trap" -- introducing an abnormally large and incompatible third-party rate-control framework to "decouple," or even breaking the original route-binding mechanism so the gateway won't start -- stop immediately after two consecutive failed corrections. Do not debate a third time.
Complete Rebuild (Third Step):
# Inspect the branch and working tree without performing recovery
git status --short
git log --oneline -5
Protect needed tracked, untracked, and ignored files, then verify the full M1 target hash and choose a recovery path in Section 10.4: consider reset only on a personal unshared branch; use revert for shared erroneous commits. A stash is not an undo and does not protect ignored files by default; Git does not restore databases or external systems. After recovery, rerun M1 acceptance to verify authentication before implementing rate limiting.
After Rebuild: Rewrite the Prompt with detailed blueprint instructions for the rate-limiting mechanism -- "use an in-memory counter to implement sliding-window rate limiting, maintain middleware-isolated state, return a unified 429 format". Then clear the now-contaminated conversation (/clear) and feed the new blueprint to a fresh AI instance.
Result: The new round of code generation precisely implements the functionality while maintaining perfect architectural elegance.
Retrospective: Mindset at Each Decision Point
| Decision Point | Mindset |
|---|---|
| Why only auth in Phase One, absolutely no rate-limiting? | Systematic dimensionality reduction -- lay foundations when laying foundations; don't let the AI leap across levels |
| Why write acceptance criteria before coding? | Acceptance-driven development -- acceptance criteria are the best instruction and also your red line |
| Why escalate architecturally instead of micromanaging after a drift? | Point out structural flaws in architect language; give the AI one or two chances to self-correct |
| Why stop after two failed corrections? | The AI has fallen into the self-consistency trap; continuing to argue only pollutes the context |
| Why choose controlled recovery followed by rebuilding? | Compare total costs including protection and verification per Section 7.5, and recover per Section 10.4 |
| Why restart the conversation after rebuilding? | Cut off the AI's historical negative memories; start fresh with clean context |