feat: add exit-transformer plugin#13343
Merged
Merged
Conversation
The exit-transformer plugin allows intercepting and transforming APISIX exit responses (e.g. plugin rejections, route-not-found errors) using user-defined Lua functions before the response is sent to the client. Users configure a list of Lua code strings. In the rewrite phase each function is registered as an exit callback via the new core.response.exit_insert_callback() API. When core.response.exit() is called anywhere in the request lifecycle, all registered callbacks receive (code, body, headers) and may return modified values. This PR also extends apisix/core/response.lua with: - exit_insert_callback(func, conf): stores callbacks in ngx.ctx per request - resp_exit: when callbacks are present, builds a structured (code, body, headers) representation from the variadic args, runs all callbacks, then sends the transformed response. Falls back to the original variadic path when no callbacks are registered, preserving full backward compatibility. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add Apache license headers to exit-transformer.lua and test file - Localize tostring to avoid luacheck global access warning in response.lua Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Pass original body (table/string) to exit callbacks before JSON encoding, matching EE behavior so body fields are accessible in user functions - After callbacks, encode table bodies to JSON with trailing newline - Change priority from 9999999 to 22950 (below real-ip/23000) to preserve existing t/core/config.t expectations - Reorder exit-transformer after real-ip in config.lua and admin/plugins.t - Fix key-auth error message: 'Missing API key found in request' was removed upstream; now 'Missing API key in request' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ntions - Rename APISIX CRD tab to APISIX Ingress Controller - Simplify admin_key note block - Fix attributes table format (add Valid values column) - Fix error message in example output Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…disabled by default) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
membphis
approved these changes
May 11, 2026
nic-6443
approved these changes
May 11, 2026
shreemaan-abhishek
approved these changes
May 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR introduces the
exit-transformerplugin and extendscore/response.luawith an exit callback mechanism to support it.Description
The
exit-transformerplugin intercepts APISIX exit responses (plugin rejections, route-not-found, auth failures, etc.) and transforms them using user-defined Lua functions before the response is sent to the client.Use cases:
401→200for legacy clients)Example
The following example wraps all error responses in a JSON envelope
{"error": <original body>}and forces the status code to200:A request without a valid API key would now receive
HTTP 200with{"error":"Missing API key in request"}instead of the defaultHTTP 401.Changes
apisix/core/response.luaTwo additions to support the callback mechanism:
exit_insert_callback(func, conf)— registers a per-request callback inngx.ctx. Each callback has the signature(code, body, headers, conf) → (code, body, headers).resp_exitwith callback path — when callbacks are registered,resp_exitbuilds a structured(code, body, headers)representation from the variadic arguments, runs all callbacks in order, then sends the transformed response. The original variadic fast path is preserved when no callbacks are present, maintaining full backward compatibility.apisix/plugins/exit-transformer.luaNew plugin. In the
rewritephase, each configured Lua function is registered as an exit callback. Functions are cached by an LRU cache to avoid repeatedload()calls.Files changed
apisix/core/response.lua— addexit_insert_callbackand callback path inresp_exitapisix/plugins/exit-transformer.lua— plugin implementationt/plugin/exit-transformer.t— test casesdocs/en/latest/plugins/exit-transformer.md— English documentationdocs/zh/latest/plugins/exit-transformer.md— Chinese documentationapisix/cli/config.lua— register plugin in default listdocs/en/latest/config.json/docs/zh/latest/config.json— add to sidebar