Rat docs

Middleware

A middleware is a service with two extras: a route pattern (match: '/...') and lifecycle hooks (before, after, on_start[], on_shutdown[]). When a request matches, the hooks run around the page handler — useful for logging, auth gates, hit counters, anything that should fire on every request without per-page wiring. The counter below is a live one.

Live: a page-view counter

main.rat — fires after every request

The page_views service matches every URL ('/**') and bumps total in its after hook. The number below reads the live state; every page you visit on this site — including this refresh — adds one.

# main.rat
> service [page_views]
match: '/**'
total: 0

after[req]
    total << total + 1

# any page
> page
<p> This site has been viewed [page_views.total] times.
Result

Total page views so far: 357

Refresh this page or visit any other doc to bump the counter.

Short-circuit with before

Auth gate on /admin

A before hook runs before the page handler. Assign to redirect or abort to bail — the page handler never runs and the user sees the alternative response. Pair with match to scope the gate to a subtree.

> service [admin_gate]
match: '/admin/**'

before[req]
    (is not session.user_id)
        redirect << '/login'

# or for an API endpoint:
> service [api_auth]
match: '/api/**'

before[req]
    (is not session.user_id)
        abort << {status: 401, body: 'unauthorized'}

Lifecycle: on_start / on_shutdown

Boot-time and drain-time work

on_start[] runs once when the server boots; on_shutdown[] runs once at SIGINT/SIGTERM (the framework calls http.Server.Shutdown after the hook returns). Useful for warming caches, opening pools, registering metrics, draining connections. They take no parameters — they're side-effect surfaces.

> service [warmup]
ready: false

on_start[]
    log('booting')
    ready << true

on_shutdown[]
    log('draining connections')

Per-request hooks

on_request_start / on_request_end fire on every URL

When you don't need URL matching but want a hook on every request — request tracing, structured access logs, request-scoped resources — declare on_request_start[] and on_request_end[]. They fire on every URL regardless of match:.

> service [tracer]

on_request_start[]
    log('begin')

on_request_end[]
    log('end')

Match patterns

Glob over the route

match is a glob over the request path. '/**' matches every route; '/api/**' matches every API call; '/admin' matches only the literal path; '/users/*/posts' uses single-segment wildcards. Multiple middlewares can match the same request — they fire in alphabetic-name order for before, reverse for after.

> service [api_log]
match: '/api/**'
hits: 0

after[req]
    hits << hits + 1
    log(req.method, req.url)

> service [request_log]
match: '/**'

after[req]
    log('served:', req.url)

That closes the advanced section. Head back to the docs index or the About page for context on how this site is built.