Zornux docs
Get started Spec

Web & APIs

Middleware

A pipeline composes cross-cutting concerns around every route in a web block — error handling, CORS, rate limiting, logging, and more — as ordered, readable English steps. No decorators, no framework plumbing.

The pipeline block

Declare a pipeline … end inside a web block. The first step is outermost: a request flows in through the steps, reaches the route, and the response flows back out through them in reverse.

zornux
controller Orders at "/orders"

    on GET "/"
        give back ok message "3 open orders"
    end

end

web OrderApp

    pipeline
        catch errors
        allow any origin
        add correlation id
        limit 100 requests per minute
        limit request size to 64 kilobytes
        log requests
        compress responses
    end

    use Orders

end

publish OrderApp on port 5000

Built-in steps

StepEffect
catch errorsA failing route answers 500 instead of crashing the host.
allow origins "…" / allow any originCORS: sets Access-Control-Allow-Origin.
add correlation idReuse or generate an X-Correlation-Id per request.
limit N requests per second|minute|hourFixed-window rate limit — 429 when exceeded (per client).
limit request size to N kilobytesReject an over-large body with 413.
log requestsA structured record per request into the host's log sink.
compress responsesReal gzip compression (with Vary) when the client accepts it.
Order is meaningful

Steps run top-to-bottom on the way in. Put catch errors first so it wraps everything, and rate/size limits before the expensive work they protect.

Custom steps

Declare your own step with step Name with request … end. Call next(request) to run the rest of the pipeline (and the route), then do something with the response before returning it — the classic wrap-around shape:

zornux
step Timing
    with request
    create response = next(request)
    # ... measure, add a header, log timing ...
    give back response
end

Add it to the pipeline like any built-in step, with use Timing:

zornux
pipeline
    catch errors
    use Timing
end
next runs the downstream

next(request) is an injected value inside a step, not a keyword. Calling it once and returning its result is the common case; you can inspect or replace the request before, and the response after.

Diagnostics are ZX2700ZX2799. Next: seeing inside a running service — Observability.