Skip to main content

exit-transformer

The exit-transformer plugin customizes responses produced through the gateway's response-exit path, including plugin rejections and route-not-found responses. It does not transform ordinary responses returned by upstream services.

Plugin priorities determine order only within the same phase and execution pass. Rewrite handlers run before access handlers, and global-rule plugins run in a separate pass from route or service plugins. _meta.priority can override a plugin's default priority. The exit-transformer rewrite handler defaults to 9999999 in API7 Gateway, placing it before most other rewrite handlers in the same pass. In APISIX, its default is 22950, below rewrite handlers such as real-ip at 23000. A response returned before exit-transformer runs is not transformed. Review the plugin execution order when combining exit-transformer with other plugins.

Transformations are defined with Lua functions using the following syntax:

return (function(code, body, header) if {{ condition }} then return {{ modified_resp }} end return code, body, header end)(...)

Examples​

The examples below demonstrate how you can use exit-transformer for different scenarios.

Enable exit-transformer Plugin​

For APISIX deployments, load exit-transformer in the gateway static configuration before configuring global rules or routes that use it. API7 Gateway users can configure the plugin through the Dashboard or Admin API when it is enabled in the installed gateway release.

For APISIX host or Docker deployments, keep the existing plugin list in config.yaml and add exit-transformer:

config.yaml
plugins:
# Keep the existing plugin list.
- exit-transformer

Reload the gateway for changes to take effect.

Modify 404 Route Not Found Response​

The following example demonstrates how you can use the plugin to update the 404 Not Found response code and header when the route does not exist. In this case, the plugin needs to be configured as a global rule plugin.

Create a global rule with the exit-transformer plugin, in which the function updates the response status code to 405 and adds a custom X-Custom-Header header if the original status code was 404:

curl -i "http://127.0.0.1:9180/apisix/admin/global_rules" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "transform-404-not-found",
"plugins": {
"exit-transformer": {
"functions": ["return (function(code, body, header) header = header or {} if code == 404 then header[\"X-Custom-Header\"] = \"Modified\" return 405, body, header end return code, body, header end)(...)"]
}
}
}'

Send a request to a route that does not exist:

curl -i "http://127.0.0.1:9080/non-existent"

You should receive an HTTP/1.1 405 Not Allowed response and observe the X-Custom-Header: Modified header.

Modify 401 Unauthorized Response for Failed Authentication​

The following example demonstrates how you can use the plugin to update the 401 Unauthorized response when authentication fails.

Create a route with the exit-transformer plugin, in which the function updates the response status code to 402 if the original status code was 401; and enable key-auth:

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

Create a consumer john:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "john"
}'

Configure key-auth credential for the consumer:

curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'

Send a request to the route without the credential:

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

You should receive an HTTP/1.1 402 Payment Required response for unauthorized access, where the response status code has been modified.

Modify Response Conditionally on Request Headers​

The following example demonstrates how you can use the plugin to conditionally modify responses based on request headers.

Create a route with the exit-transformer plugin, in which the function updates the response status code by Content-Type header. If the header value is application/json and the original status code is 404, update the response status code to 405. Print warning messages inside and outside the condition evaluation for demonstration purposes.

curl -i "http://127.0.0.1:9180/apisix/admin/global_rules" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "transform-by-header-condition",
"plugins": {
"exit-transformer": {
"functions": [
"return
(function(code, body, header)
local core = require(\"apisix.core\")
local ct = ngx.req.get_headers()[\"Content-Type\"]
core.log.warn(\"exit transformer logics running outside the condition\")
if ct == \"application/json\" and code == 404 then
core.log.warn(\"exit transformer logics running inside the condition\")
return 405
end
return code, body, header
end)
(...)"
]
}
}
}'

Send a request to a route that does not exist, without any header:

curl -i "http://127.0.0.1:9080/non-existent"

You should receive an HTTP/1.1 404 Not Found response and see the following message in the log:

exit transformer logics running outside the condition

Send a request to the non-existent route with the JSON Content-Type header:

curl -i "http://127.0.0.1:9080/non-existent" -H "Content-Type: application/json"

You should receive an HTTP/1.1 405 Not Allowed response, where the response status code has been modified, and see the following message in the log:

exit transformer logics running outside the condition
exit transformer logics running inside the condition