Iwf Guide
Config and Server
Configuration is plain Idris data. Apps can build it directly, derive it from environment variables in app code, and attach it to the app runner.
1. AppConfig
record AppConfig where
constructor MkAppConfig
mode : EnvMode
port : Int
database : DatabaseConfig
session : SessionConfig
logging : LoggingConfig
maxRequestBytes : Int
Use defaultConfig locally and productionConfig in production:
appConfig : AppConfig
appConfig =
withLogLevel Info
(withMaxRequestBytes 131072
(withPort 8082
(productionConfig sessionSecret databaseUrl)))
Common modifiers:
withModewithPortwithDatabaseUrlwithDatabaseStatementTimeoutwithDatabaseTransactionTimeoutwithSessionSecretwithSecureSessionCookieswithLogLevelwithMaxRequestBytes
Database timeouts are passed through to the PostgreSQL runtime helper:
config : AppConfig
config =
withDatabaseTransactionTimeout 5000
(withDatabaseStatementTimeout 2000 defaultConfig)
2. Environment Modes
EnvMode is one of:
DevelopmentTestProduction
Use isDevelopment, isTest, and isProduction in app code when behavior really needs to vary by environment.
3. Sessions
SessionConfig controls the signed session cookie:
secureSessionConfig : String -> SessionConfig
secureSessionConfig secret =
MkSessionConfig "iwf_session" secret True True "Lax"
Production should use secure, HTTP-only cookies and a real secret:
config : AppConfig
config = productionConfig sessionSecret databaseUrl
validateProductionConfig reports common mistakes such as development mode, the default session secret, or insecure cookies.
4. App Startup
Run the app through app and runApp:
main : IO ()
main =
runApp
(app "My App" routes
|> withAppConfig appConfig)
runApp:
- mounts default framework assets
- uses configured logging
- enforces
maxRequestByteswith413 Payload Too Large - rejects malformed request lines and headers with
400 Bad Request - listens on
127.0.0.1:<port> - handles accepted clients concurrently
- can be paired with advanced supervisor/test shutdown hooks
- dispatches requests through the route registry
- closes each response connection explicitly; streaming is not part of the built-in server contract yet
For small demos, use the default app config:
main : IO ()
main =
runApp (app "My App" routes)
Common app runner modifiers:
withAppConfigwithPortwithProductionwithDatabaseFromEnvwithSessionSecretFromEnvwithAuthwithAutoRefresh
5. Graceful Shutdown
Most apps can let the process supervisor stop the app process. Advanced embedding and test harnesses can use the lower-level server control API when they need to stop the listener and wait for accepted requests to finish.
Shutdown closes the listening socket, stops accepting new clients, closes each accepted connection after its response, and waits until active handlers drain. Those hooks live behind the explicit Iwf.Server.Advanced import.
6. Built-In Server Contract
The built-in server is intentionally small and non-streaming:
- each accepted TCP connection is read once with
recv maxRequestBytes - the request payload is held in memory while it is parsed and dispatched
- request bodies larger than
maxRequestBytesreturn413 Payload Too Large - malformed request lines or headers return
400 Bad Request - each handler returns a complete
Responsevalue before bytes are written - responses are rendered with
Content-Length HEADresponses keep headers but render an empty body- every accepted connection is closed after one response
- HTTP keep-alive, chunked request bodies, request streaming, and response streaming are not part of the built-in server contract
7. Logging
LoggingConfig contains a level and structured flag. By default, the server emits colorized request/response logs with timing metadata through Iwf.Log. Set structured = True if you want the older single-line key/value format.
logging : LoggingConfig
logging = MkLoggingConfig Info False
Diagnostics from framework subsystems use Iwf.Diagnostic, with areas for routes, forms, auth, migration, and database typegen.
Next
Read Routing.