Iwf Guide

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:

  • withMode
  • withPort
  • withDatabaseUrl
  • withDatabaseStatementTimeout
  • withDatabaseTransactionTimeout
  • withSessionSecret
  • withSecureSessionCookies
  • withLogLevel
  • withMaxRequestBytes

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:

  • Development
  • Test
  • Production

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 maxRequestBytes with 413 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:

  • withAppConfig
  • withPort
  • withProduction
  • withDatabaseFromEnv
  • withSessionSecretFromEnv
  • withAuth
  • withAutoRefresh

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 maxRequestBytes return 413 Payload Too Large
  • malformed request lines or headers return 400 Bad Request
  • each handler returns a complete Response value before bytes are written
  • responses are rendered with Content-Length
  • HEAD responses 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.