Skip to main content
Version: 3.17

exit-transformer

Description#

The exit-transformer Plugin intercepts responses generated by APISIX itself — such as authentication failures, rate-limit rejections, or upstream errors — and transforms them using user-defined Lua functions before sending to the client.

The Plugin registers callbacks that are invoked when core.response.exit() is called, receiving the response (status_code, body, headers) as arguments and returning the (possibly modified) values. Multiple functions can be chained, and each function's output becomes the next function's input.

note

This Plugin only transforms responses generated by APISIX's own core.response.exit() mechanism. It does not transform responses that originate from upstream services.

Attributes#

NameTypeRequiredDefaultValid valuesDescription
functionsarray[string]TrueAn array of Lua function source strings. Each string must be a complete Lua chunk that returns a function. The function receives (status_code, body, headers) and must return status_code, body, headers (modified or unchanged). If a function throws an error, it is logged and the original values are passed to the next function.

Each Lua function string must be a chunk that evaluates to a function with the following signature:

return (function(code, body, header)
-- modify code, body, or header as needed
return code, body, header
end)(...)

Examples#

The examples below demonstrate how you can configure exit-transformer in different scenarios.

note
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')

Remap Status Codes#

The following example demonstrates how to remap a 404 Not Found response to 405 Method Not Allowed.

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "exit-transformer-route",
"uri": "/anything",
"plugins": {
"key-auth": {},
"exit-transformer": {
"functions": [
"return (function(code, body, header) if code == 401 then return 403, body, header end return code, body, header end)(...)"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {"httpbin.org:80": 1}
}
}'

Send a request without an API key:

curl -i "http://127.0.0.1:9080/anything"

You should receive a 403 Forbidden response instead of the default 401 Unauthorized.

Normalize Error Response Format#

The following example demonstrates how to rewrite any error response body to a consistent JSON format and add a custom header.

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "exit-transformer-route",
"uri": "/anything",
"plugins": {
"key-auth": {},
"exit-transformer": {
"functions": [
"return (function(code, body, header) if code and code >= 400 then header = header or {} header[\"X-Error-Code\"] = tostring(code) body = {error = true, status = code, message = (type(body) == \"table\" and body.message) or \"request failed\"} end return code, body, header end)(...)"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {"httpbin.org:80": 1}
}
}'

Send a request without an API key:

curl -i "http://127.0.0.1:9080/anything"

You should receive a 401 response with a normalized JSON body and the X-Error-Code: 401 header:

{"error":true,"status":401,"message":"Missing API key in request"}