ADR-0012: Dynamic API Prefixing and Service Namespacing
- Status: Implemented
- Date: 2026-05-11
Context
As Framework M moves towards a macroservice architecture, micro-frontends (MFEs) need to communicate with their respective backend services without hardcoding full URLs or being statically bound to a specific deployment path.
In a multi-service deployment, the backend might be structured as:
/api/finance/v1/.../api/inventory/v1/.../api/hr/v1/...
However, during local development or in a monolithic deployment, these might all live under a single /api/v1 prefix.
Previously, the frontend Desk and plugins assumed a flat /api/v1 structure. This created "cliffs" when moving from a monolith to a distributed macroservice deployment, as MFEs would try to hit the wrong endpoints.
Decision
Implement Dynamic API Prefixing and Service Namespacing across the entire stack.
1. Build-Time Service Injection
The @framework-m/vite-plugin now injects the FRAMEWORK_M_SERVICE_NAME environment variable into the frontend build via Vite's define configuration. This allows an MFE to know which "service" it belongs to at build/runtime.
2. Runtime URL Construction
The frontend constants (API_URL, META_URL, WS_URL) in framework-m-desk now dynamically construct endpoints:
- If a service name is present, they use
/api/{service}/v1. - If an absolute base URL is provided (via
__FRAMEWORK_CONFIG__), they normalize it by ensuring the correct versioned/service-prefixed path is appended if missing. - They prioritize explicit configuration overrides (e.g.,
wsBaseUrl) while maintaining robust fallbacks.
3. Namespaced Resource Resolution
The frameworkMDataProvider (and the underlying buildResourceUrl helper) now supports namespaced resource strings (e.g., finance/PurchaseInvoice).
- When a namespaced resource is requested, the provider splits it into
serviceandresource. - It reconstructs the URL to point to the correct service-scoped endpoint (e.g.,
http://base.com/api/finance/v1/PurchaseInvoice). - This allows a central "Shell" to communicate with multiple federated macroservices seamlessly.
4. Backend Prefixing (Macroservice Mode)
The Python WebAdapter in framework-m-standard is updated to automatically apply the /api/{service_name}/{version} prefix to all registered routers when the application is running in Macroservice mode.
5. Naming & Versioning Governance
- Service Names: Must be lowercase (e.g.,
finance,inventory). - Resource Namespacing: Resources across services use the
service/DocTypepattern. - Environment Parity: The injected
FRAMEWORK_M_SERVICE_NAMEmust exactly match the namespace used in cross-service resource resolution. - Version Control: The
api_version(e.g.,v1,v2) is a Framework-level configuration concern. It is managed viaFRAMEWORK_API_VERSION(backend) andwindow.__FRAMEWORK_CONFIG__.apiVersion(frontend). Individual app developers MUST NOT hardcode these versions in their code or routing logic.
Consequences
Positive
- Architectural Isolation: MFEs are no longer bound to a flat global namespace.
- Zero-Cliff Migration: The same MFE code works in both Monolith (
/api/v1) and Macroservice (/api/{service}/v1) modes without changes. - Improved Proxying: Clearer path-based routing for API gateways and reverse proxies.
Negative
- Complexity: URL construction logic is more complex than simple concatenation.
- Dependency: MFEs must be built with the correct
FRAMEWORK_M_SERVICE_NAMEenvironment variable if they require namespacing.