HTTP middleware for multi-tenant request handling (imperative shell).
This namespace provides middleware for tenant resolution and database schema switching in multi-tenant applications following the schema-per-tenant pattern.
Features:
Based on: docs/adr/ADR-004-multi-tenancy-architecture.md
HTTP middleware for multi-tenant request handling (imperative shell). This namespace provides middleware for tenant resolution and database schema switching in multi-tenant applications following the schema-per-tenant pattern. Features: - Subdomain-based tenant resolution - JWT claim fallback for API access - Database schema switching per request - Tenant caching for performance - Error handling for missing/invalid tenants Based on: docs/adr/ADR-004-multi-tenancy-architecture.md
(wrap-multi-tenant handler tenant-service db-context)(wrap-multi-tenant handler tenant-service db-context options)Combined middleware for full multi-tenant support.
Applies both tenant resolution and schema switching in correct order. Convenience function for common use case.
Args: handler: Ring handler function tenant-service: ITenantService implementation db-context: Database context with connection pool options: Map with optional configuration (passed to wrap-tenant-resolution): :require-tenant? - If true, return 404 when tenant not found (default: false) :cache - Atom for tenant cache (default: creates new cache)
Returns: Ring middleware function
Example: (wrap-multi-tenant handler tenant-service db-context {:require-tenant? true})
Combined middleware for full multi-tenant support.
Applies both tenant resolution and schema switching in correct order.
Convenience function for common use case.
Args:
handler: Ring handler function
tenant-service: ITenantService implementation
db-context: Database context with connection pool
options: Map with optional configuration (passed to wrap-tenant-resolution):
:require-tenant? - If true, return 404 when tenant not found (default: false)
:cache - Atom for tenant cache (default: creates new cache)
Returns:
Ring middleware function
Example:
(wrap-multi-tenant handler tenant-service db-context {:require-tenant? true})(wrap-tenant-resolution handler tenant-service)(wrap-tenant-resolution handler
tenant-service
{:keys [require-tenant? cache]
:or {require-tenant? false
cache (create-tenant-cache)}})Middleware to resolve tenant from request and add to request context.
Extracts tenant information from subdomain, JWT, or headers and looks up the tenant entity from the database. Adds tenant to request map for use by downstream handlers.
Tenant extraction priority:
If no tenant is found and tenant is required, returns 404 response. If tenant is optional (require-tenant? = false), continues without tenant.
Args: handler: Ring handler function tenant-service: ITenantService implementation options: Map with optional configuration: :require-tenant? - If true, return 404 when tenant not found (default: false) :cache - Atom for tenant cache (default: creates new cache)
Returns: Ring middleware function
Example: (wrap-tenant-resolution handler tenant-service {:require-tenant? true})
Middleware to resolve tenant from request and add to request context.
Extracts tenant information from subdomain, JWT, or headers and looks up
the tenant entity from the database. Adds tenant to request map for use
by downstream handlers.
Tenant extraction priority:
1. Subdomain (acme-corp.myapp.com → tenant_acme_corp schema)
2. JWT claim (from authenticated user)
3. HTTP header (X-Tenant-Slug or X-Tenant-Id)
If no tenant is found and tenant is required, returns 404 response.
If tenant is optional (require-tenant? = false), continues without tenant.
Args:
handler: Ring handler function
tenant-service: ITenantService implementation
options: Map with optional configuration:
:require-tenant? - If true, return 404 when tenant not found (default: false)
:cache - Atom for tenant cache (default: creates new cache)
Returns:
Ring middleware function
Example:
(wrap-tenant-resolution handler tenant-service {:require-tenant? true})(wrap-tenant-schema handler db-context)Middleware to switch database schema based on tenant in request.
Uses the tenant entity in request (added by wrap-tenant-resolution) to switch the database search_path to the tenant's schema. This enables schema-per-tenant multi-tenancy where each tenant has isolated tables.
IMPORTANT: This middleware must run AFTER wrap-tenant-resolution.
The database search_path is set to:
If no tenant is in request, the database schema is NOT changed (remains public).
Args: handler: Ring handler function db-context: Database context with connection pool
Returns: Ring middleware function
Example: (-> handler (wrap-tenant-resolution tenant-service) (wrap-tenant-schema db-context))
Middleware to switch database schema based on tenant in request.
Uses the tenant entity in request (added by wrap-tenant-resolution) to
switch the database search_path to the tenant's schema. This enables
schema-per-tenant multi-tenancy where each tenant has isolated tables.
IMPORTANT: This middleware must run AFTER wrap-tenant-resolution.
The database search_path is set to:
- Tenant schema (e.g., tenant_acme_corp) - for tenant-specific tables
- public schema - for shared tables (tenants, auth_users)
If no tenant is in request, the database schema is NOT changed (remains public).
Args:
handler: Ring handler function
db-context: Database context with connection pool
Returns:
Ring middleware function
Example:
(-> handler
(wrap-tenant-resolution tenant-service)
(wrap-tenant-schema db-context))cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |