Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Response Callbacks

After Mycelium forwards a request to a downstream service and receives a response, it can optionally run callbacks — side effects triggered by the response. Use callbacks to log metrics, notify third-party services, or trigger async workflows without modifying the downstream service.

Callbacks run after the response has been returned to the caller. They never block or modify the response.


How it works

Client → Mycelium → Downstream service
                         ↓ response
Mycelium returns response to client
       ↓ (in parallel or fire-and-forget)
Callbacks execute

Defining a callback

Callbacks are defined in config.toml under [api.callbacks], then referenced by name on individual routes.

Rhai callback — inline script

Rhai is an embedded scripting language. Write the script directly in the config file. No external files or interpreters required.

[api.callbacks]

[[callback]]
name = "error-monitor"
type = "rhai"
script = """
if status_code >= 500 {
    log_error("Server error: " + status_code);
}
if duration_ms > 1000 {
    log_warn("Slow response: " + duration_ms + "ms");
}
"""
timeoutMs = 1000

Available variables inside the script: status_code, duration_ms, headers (map), method, upstream_path. Logging functions: log_info, log_warn, log_error.

HTTP callback — POST the response context to a URL

[[callback]]
name = "audit-log"
type = "http"
url = "https://audit.internal/events"
method = "POST"          # default
timeoutMs = 3000
retryCount = 3
retryIntervalMs = 1000

Python callback — run a script

[[callback]]
name = "metrics-push"
type = "python"
scriptPath = "/opt/mycelium/callbacks/push_metrics.py"
pythonPath = "/usr/bin/python3.12"
timeoutMs = 5000

JavaScript callback — run a Node.js script

[[callback]]
name = "slack-notify"
type = "javascript"
scriptPath = "/opt/mycelium/callbacks/notify_slack.js"
nodePath = "/usr/bin/node"
timeoutMs = 3000

Attaching a callback to a route

Reference the callback by name in the route’s callbacks field:

[api.services]

[[my-service]]
host = "localhost:3000"
protocol = "http"

[[my-service.path]]
group = "protected"
path = "/api/*"
methods = ["POST", "PUT"]
callbacks = ["audit-log", "metrics-push"]

Multiple callbacks can be attached to the same route.


Filtering which responses trigger the callback

By default, a callback runs for every response. Use filters to narrow this:

[[callback]]
name = "error-alert"
type = "http"
url = "https://alerts.internal/errors"

# Only trigger on 5xx responses
triggeringStatusCodes = { oneof = [500, 502, 503, 504] }

# Only trigger on POST and DELETE
triggeringMethods = { oneof = ["POST", "DELETE"] }

# Only trigger if the response has a specific header
triggeringHeaders = { oneof = { "X-Error-Code" = "PAYMENT_FAILED" } }

Filter statement types:

  • oneof — at least one value must match
  • allof — all values must match
  • noneof — none of the values may match

Execution mode

Control how callbacks run globally:

[api]
callbackExecutionMode = "fireAndForget"  # default
ModeBehavior
fireAndForgetCallbacks run in background tasks; gateway does not wait for them
parallelAll callbacks run concurrently; gateway waits for all to finish
sequentialCallbacks run one after another; gateway waits

Use fireAndForget (default) when callback latency should not affect response time. Use sequential when order matters (e.g., log before notify).


What the callback receives

Each callback receives a context object with information about the completed request:

FieldDescription
status_codeHTTP status code returned by the downstream service
response_headersResponse headers
duration_msTime from gateway forwarding to downstream response
upstream_pathThe path the client called
downstream_urlThe URL Mycelium forwarded to
methodHTTP method
timestampISO 8601 timestamp
request_idValue of x-mycelium-request-id if present
client_ipCaller’s IP address
user_infoAuthenticated user info (email, account ID) — present when route is authenticated or higher
security_groupThe security group that was applied

For HTTP callbacks, this context is sent as a JSON POST body. For Python / JavaScript callbacks, the context is passed as a JSON-serialized argument. For Rhai callbacks, these fields are available as global variables in the script.


Reference — callback fields

FieldTypeRequiredDescription
namestringYesUnique name — used to reference the callback from routes
typerhai / http / python / javascriptYesCallback engine
timeoutMsintegerNoMax execution time in ms (default: 5000). Ignored in fireAndForget mode
retryCountintegerNoHow many times to retry on failure (default: 3)
retryIntervalMsintegerNoWait between retries in ms (default: 1000)
scriptstringRhai onlyInline Rhai script source
urlstringHTTP onlyTarget URL
methodstringHTTP onlyPOST, PUT, PATCH, or DELETE (default: POST)
scriptPathpathPython / JavaScript onlyPath to script file
pythonPathpathPython onlyInterpreter path (default: system python3)
nodePathpathJavaScript onlyNode.js path (default: system node)
triggeringMethodsobjectNoFilter by HTTP method (oneof, allof, noneof)
triggeringStatusCodesobjectNoFilter by response status code
triggeringHeadersobjectNoFilter by response header key/value