Skip to main content

The Context Object

The Context holds all state for one request as it travels through a policy graph. It is created when a route matches, passed to every node in turn, and whatever its response field contains when execution finishes is what the client receives. Each plugin may read and mutate any part of it.

Context
├── request # the inbound request (plugins may rewrite it before proxying)
├── response # the response under construction
├── message # free-form key/value scratch space for inter-node data
└── errors # errors accumulated during graph execution

context.request

A protocol-agnostic snapshot of the inbound request, populated by the listener:

FieldTypeNotes
methodstringGET, POST, ...
pathstringRequest path without the query string
hoststringValue of the Host header; empty string when absent
schemestringDefaults to http when the URI carries none
headersmap of string → list of stringMulti-valued; headers may repeat
query_paramsmap of string → list of stringMulti-valued; parameters may repeat
bodybytesFully buffered
remote_addrstringClient socket address as ip:port
protocolenumhttp1 or http2 (see note below)

Transform plugins such as proxy-rewrite modify this before the upstream plugin forwards it — for example stripping a path prefix or removing headers.

context.response

Initially empty. Populated by the upstream plugin (with the backend's reply) or by any plugin that short-circuits, such as an auth plugin returning 401 or an error-handler rendering a custom body. Downstream nodes may inspect or modify it.

FieldTypeNotes
status_codeu160 means unset — no node has written a status yet
headersmap of string → list of string
bodybytes

When graph execution finishes, a status_code of 0 is treated as 200 by the server before the response is sent to the client.

context.message

A free-form key/value map (string → JSON value) that the gateway imposes no schema on. Plugins use it to pass data to downstream nodes:

  • the jwt-auth plugin validates the token and extracts its claims into context.message for downstream nodes (for example a logging plugin) to read;
  • a Lua script node can set arbitrary keys (ctx.message.processed_by = "lua-plugin") and read keys written by earlier nodes.

Because there is no schema, the convention around key names is defined by your policy — which nodes write what, and which nodes read it.

context.errors

An append-only list of errors accumulated during graph execution. When a node fails, the engine tags the error with the failing node's id, appends it here, and routes the context through the error path — see Error handling. Each entry records:

FieldTypeNotes
node_idstringId of the node that produced the error
codestringMachine-readable code, e.g. unauthorized, rate_limited
messagestringHuman-readable description
metadatamap of string → JSON valueOptional structured details

Errors do not abort the pipeline by themselves; they redirect where execution goes next.

Serialization

The Context is serializable so it can be marshalled to and from Lua scripts (and rendered as JSON). Request and response bodies are encoded as base64 strings during serialization, keeping binary payloads intact through JSON/Lua round-trips. Inside a Lua script the context arrives as a native table mirroring the structure above.

note

The protocol enum produces http1, http2, and websocket (a client WebSocket upgrade runs the policy graph with protocol: websocket before the relay starts). The tcp and udp variants remain reserved: L4 stream proxying is implemented but bypasses the HTTP engine entirely, so no Context is built for raw streams. A Python scripting runtime that would marshal the same Context into Python dicts is planned but not implemented.