The pieces
ApivalkConfiguration is the single object that holds the runtime wiring. Apivalk (the entry point) takes one and does nothing else — so everything you do to customise the framework happens on the configuration.
A full constructor looks like this:
Minimal bootstrap
The smallest workingindex.php:
GET /health route goes through Sanitize → Validate → Controller and returns JSON.
Adding authentication
AuthenticationMiddleware populates the identity; SecurityMiddleware enforces it. Always add them in that order:
Adding a PSR-11 container
If you pass a container, Apivalk uses it to build controllers — so constructor injection works:new $controllerClass(), so constructor-less controllers still work.
Adding a logger
Apivalk accepts any PSR-3 logger and exposes it via$apivalk->getLogger():
Localization
See the full Localization reference. The short version:Locale::en().
Middleware order (LIFO onion)
MiddlewareStack::handle() reverses the list, so the last middleware you add() is the innermost layer (closest to the controller). That means:
SanitizeMiddlewareandRequestValidationMiddlewarerun as close to the controller as possible → add them last.AuthenticationMiddlewaremust run beforeSecurityMiddleware(authentication before authorization) → add Authentication first, Security second.RateLimitMiddlewareusually runs before anything expensive → add early.
How to extend your configuration
A rawindex.php with every middleware listed inline is fine for a small service but gets noisy fast. Grow into one of these patterns:
1. Move bootstrapping into an application class
Wrap everything the request-scoped entry point needs in a factory:public/index.php then shrinks to:
2. Register middlewares through the container
Pull middlewares out of the bootstrap file and into the container as first-class services. That lets them take dependencies (database, PSR-3 logger, cache, feature flags) without you constructing them by hand:3. Swap the renderer or exception handler per environment
JsonRenderer and ApivalkExceptionHandler::handle are defaults, not requirements. Both are constructor arguments:
RendererInterface implementation when you need non-JSON output or custom envelopes; ship your own exception handler when you need to integrate with Sentry / Datadog / Bugsnag.
4. Keep framework bridges thin
If you’re running inside Laravel or Symfony, use the framework bridges rather than re-implementing wiring. The bridges do theApivalkBootstrap work and hand you an Apivalk instance tuned for that framework’s lifecycle.