The Middleware That Eliminated Every Config Lookup
How hierarchical configuration with automatic injection made manual ConfigService calls vanish
This article is part of the “Building with AI” series documenting my journey using multi-agent AI workflows to build production systems.All examples are from personal projects and do not represent employer technologies.
January 2026. My SaaS platform had configuration chaos:
JWT expiration hardcoded in 3 places
Each crate reading std::env::var() directly
No tenant-specific overrides
Zero hierarchy (Platform → Tenant → Capsule)
Worse: Every handler manually called ConfigService.get() with different error handling patterns. Inconsistent, error-prone, and impossible to enforce.AI Focus: Could AI design a middleware pattern that makes configuration automatic and hierarchical?System Example: ConfigMiddleware that injects resolved config into every request via web::ReqData<ConfigContext>.
I provided the hierarchy requirements and reviewed the middleware ordering logic. AI initially missed that ConfigMiddleware depends on CapsuleExtractor—I caught that in verification.Also added the caching strategy: Moka cache with 10K entries, 5-minute TTL to prevent DynamoDB hammering.
5,541 lines of infrastructure added. 28 new tests. 382 existing eva-auth tests still passing. Zero handlers calling ConfigService.get() directly anymore.
Mistake: Initially registered ConfigMiddleware BEFORE CapsuleExtractor in the middleware chain.Why it failed: ConfigMiddleware needs CapsuleContext to know which tenant/capsule config to load. Without CapsuleExtractor running first, it had no scope information.How we fixed it: Reversed the middleware order in main.rs:
Copy
// WRONG ORDERApp::new() .wrap(ConfigMiddleware::new(config_service)) // Runs first .wrap(CapsuleExtractor::new()) // Runs second// CORRECT ORDERApp::new() .wrap(CapsuleExtractor::new()) // Runs first .wrap(ConfigMiddleware::new(config_service)) // Runs second
Lesson: AI designed both middleware pieces correctly but didn’t understand middleware execution order in Actix-web. Middleware wraps happen in reverse order—humans need to know the framework.
We also exposed configuration management via REST API (10 endpoints):Platform Config:
Copy
GET /api/platform/config/authPUT /api/platform/config/authPOST /api/platform/config/auth/reset
Tenant Config:
Copy
GET /api/{tenant_id}/config/authPUT /api/{tenant_id}/config/authDELETE /api/{tenant_id}/config/auth
Capsule Config:
Copy
GET /api/{tenant_id}/capsules/{capsule_id}/config/authPUT /api/{tenant_id}/capsules/{capsule_id}/config/authDELETE /api/{tenant_id}/capsules/{capsule_id}/config/authPOST /api/{tenant_id}/capsules/{capsule_id}/config/auth/preview
The preview endpoint is clever—it shows what config would resolve to without saving:
Copy
POST /api/tenant-123/capsules/DEVUS/config/auth/preview{ "jwt_expiration_seconds": 300}Response:{ "effective_config": { "jwt_expiration_seconds": 300, // Your override "refresh_token_ttl_seconds": 7200, // From tenant "enable_ses": true // From platform }, "source": { "jwt_expiration_seconds": "capsule", "refresh_token_ttl_seconds": "tenant", "enable_ses": "platform" }}
This lets admins see the full hierarchy before committing changes.
AI excels at middleware pattern design once you explain the data flow. It generated the entire ConfigMiddleware + caching + API layer in one go.
AI Weakness
AI doesn’t understand framework-specific execution order. It designed both middleware correctly but registered them in the wrong order.
Human Role
Humans define the hierarchy requirements, review middleware ordering, and add performance optimizations (caching, TTL values).
Process Insight
The best AI-generated infrastructure has a single integration point (main.rs middleware registration). Makes it easy to test and migrate incrementally.
Middleware over manual calls - Inject config via middleware so handlers can’t forget to load it. Compiler enforcement is better than documentation.
Cache at the service layer - Put Moka/Redis in front of your config backend. Our cache hit rate is 99.2% (single 5-min TTL).
Preview before commit - Add a preview endpoint that shows effective config without saving. Prevents production misconfigurations.
Pro tip: Use web::ReqData<T> in Actix-web for type-safe middleware injection. If a handler declares config: web::ReqData<ConfigContext>, it won’t compile unless ConfigMiddleware is registered. Zero runtime errors.
How do you handle configuration in multi-tenant systems? Manual lookups or automatic injection?Connect on LinkedIn or comment on the YouTube Short
Disclaimer: This content represents my personal learning journey using AI for a personal project. It does not represent my employer’s views, technologies, or approaches.All code examples are generic patterns or pseudocode for educational purposes.