Looking for the plugin's configuration parameters? You can find them in the Exit Transformer configuration reference doc.
Transform and customize Kong Gateway response exit messages using Lua functions. The plugin’s capabilities range from changing messages, status codes, and headers, to completely transforming the structure of Kong Gateway responses.
untrusted-lua
must be set to eitheron
orsandbox
in yourkong.conf
file for this plugin to work. The default value issandbox
, which means that Lua functions are allowed, but will be executed in a sandbox which has limited access to the Kong global environment.
Transforming 4xx and 5xx Responses
By default, the Exit Transformer is only applied to requests that match its criteria (its route or service matching configuration) or globally within a workspace.
Handling Unmatched 400 and 404 Responses
Requests that result in 400 or 404 responses neither match any criteria nor fall
within any specific Workspace, and standard plugin criteria will never match those
responses. You can designate Exit Transformer configurations that do handle these
responses by enabling the handle_unexpected
(400) and handle_unknown
(404) settings:
- The
handle_unknown
parameter must be used on a globally configured instance of the plugin running in the default workspace, and only takes effect when a 404 error occurs. - The
handle_unexpected
parameter can be enabled for any plugin configuration - on a service, on a route, and so on. It only takes effect when a 400 error occurs.
It’s not a prerequisite for handle_unexpected
to also have handle_unknown
set,
if an unexpected error happened within some known service or route context. If a
configuration has both handle_unknown
and handle_unexpected
enabled, then an
unexpected error on an unknown service or route will pass through the Exit Transformer plugin.
HTTP Response Status Codes
4xx codes are client error responses:
- 400 Bad request
- 401 Unauthorized
- 402 Payment required
- 403 Forbidden
- 404 Not found
- 405 Method not allowed
- 406 Not acceptable
- 407 Proxy authentication required
- 409 Conflict
- 410 Gone
- 411 Length required
- 412 Precondition failed
- 413 Payload too large
- 414 URI too long
- 415 Unsupported media type
- 416 Range not satisfiable
- 417 Expectation failed
- 418 I’m a teapot
- 421 Misdirected request
- 422 Unprocessable entity
- 423 Locked
- 424 Failed dependency
- 425 Too early
- 426 Upgrade required
- 428 Precondition required
- 429 Too many requests
- 431 Request header fields too large
- 451 Unavailable for legal reasons
- 494 Request header or cookie too large (Nginx-specific)
5xx codes are server error responses:
- 500 An unexpected error occurred
- 501 Not implemented
- 502 An invalid response was received from the upstream server
- 503 The upstream server is currently unavailable
- 504 The upstream server is timing out
- 505 HTTP version not supported
- 506 Variant also negotiates
- 507 Insufficient storage
- 508 Loop detected
- 510 Not extended
- 511 Network authentication required
Function Syntax
The Exit Transformer plugin expects a configuration function to be Lua code that returns a function accepting three arguments: status, body, and headers.
Any Kong exit call exposed on the proxy side gets reduced through these functions.
Kong -> f(status, body, headers) -> ... -> exit(status, body, headers)
Caution:
kong.response.exit()
requires astatus
argument only.body
andheaders
may benil
. If you manipulate the body and headers, first check that they exist and instantiate them if they do not exist.
If you manipulate body and headers, see the Modify the body and headers regardless if provided example below.
Example Lua Functions
Identity function that does not transform the exit responses
return function(status, body, headers)
return status, body, headers
end
Function that always returns a 200 status code with status bundled within the message
return function(status, body, headers)
-- identity
if not body or not body.message then
return status, body, headers
end
body.status = status
return 200, body, headers
end
Customize particular Kong messages
local responses = {
["No API key found in request"] = {
message = "Please provide an API key",
status = 418,
headers = { ["x-some-header"] = "some value" },
},
["Invalid authentication credentials"] = {
message = "Invalid API key",
},
-- ...
}
return function(status, body, headers)
if not body or not body.message then
return status, body, headers
end
local response = responses[body.message]
body.message = response.message or body.message
status = response.status or status
headers = response.headers or headers
return status, body, headers
end
Modify the body and headers regardless if provided
return function(status, body, headers)
if not body then
body = { message = "This replaces a formerly empty body" }
else
body.message = "This replaces a formerly non-empty body"
end
if not headers then
headers = { ["X-Message"] = "This adds X-Message to an empty set of headers" }
else
headers["X-Message"] = "This adds X-Message to an existing set of headers"
end
return status, body, headers
end
Demonstration
-
Create a service in Kong:
curl -i -X POST http://localhost:8001/services \ --data name=example.com \ --data url='https://httpbin.konghq.com'
-
Create a route in Kong:
curl -i -X POST http://localhost:8001/services/example.com/routes \ --data 'hosts[]=example.com'
-
Create a file named
transform.lua
with the transformation code. The following example adds a header, appends “arr!” to any message, and addserror
andstatus
fields on the response body. Save this file in a location referenced by thelua_package_path
variable.-- transform.lua return function(status, body, headers) if not body or not body.message then return status, body, headers end headers = { ["x-some-header"] = "some value" } local new_body = { error = true, status = status, message = body.message .. ", arr!", } return status, new_body, headers end
-
Configure the
exit-transformer
plugin withtransform.lua
.curl -X POST http://localhost:8001/services/example.com/plugins \ -F "name=exit-transformer" \ -F "config.functions=@transform.lua"
-
Add the
key-auth
plugin to test a forced generation of an exit transform response in the following step:curl -X POST http://localhost:8001/services/example.com/plugins \ --data "name=key-auth"
-
Test a forced generation of an exit response.
Attempt a request to the service to get the custom error. Because the request did not provide credentials (API key), a 401 response is returned in the message body.
curl --header 'Host: example.com' 'localhost:8000'
Response:
HTTP/1.1 200 OK ... X-Some-Header: some value { "error": true, "status": 401, "kong_message": "No API key found in request, arr!" }
Apply the plugin globally to handle unknown responses
The plugin can also be applied globally:
curl -X POST http://localhost:8001/plugins/ \
-F "name=exit-transformer" \
-F "config.handle_unknown=true" \
-F "config.functions=@transform.lua"
...
curl --header 'Host: non-existent.com' 'localhost:8000'
Response:
HTTP/1.1 200 OK
...
X-Some-Header: some value
{
"error": true,
"status": 404,
"kong_message": "No Route matched with those values, arr!"
}
Custom errors by MIME type
This example shows a use case where you want custom JSON and HTML responses based on an Accept header.
Create a file named custom-errors-by-mimetype.lua
with the transformation
code shown below. Include the status codes you want to customize. See the full list
of HTTP response codes above. Any status code not listed in the
custom-errors-by-mimetype.lua
file will use the default
response The upstream server responded with <status code>
.
local template = require "resty.template"
local split = require "kong.tools.utils".split
local HTTP_MESSAGES = {
s400 = "Bad request",
s401 = "Unauthorized",
-- ...
-- See HTTP Response Status Codes section above for the full list
s511 = "Network authentication required",
default = "The upstream server responded with %d"
}
local function get_message(status)
return HTTP_MESSAGES["s" .. status] or HTTP_MESSAGES.default.format(status)
end
local html = template.compile([[
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Some Title</title>
</head>
<body>
<h1>HTTP </h1>
<p></p>
<img src="https://thumbs.gfycat.com/RegularJointEwe-size_restricted.gif"/>
</body>
</html>
]])
-- Customize responses based on content type
local formats = {
["application/json"] = function(status, message, headers)
return status, { status = status, error = message }, headers
end,
["text/html"] = function(status, message, headers)
return status, html { status = status, error = message }, headers
end,
}
return function(status, body, headers)
if status < 400 then
return status, body, headers
end
local accept = kong.request.get_header("accept")
-- Gets just first accept value. Can be improved to be compliant quality
-- etc parser. Look into kong.pdk.response get_response_type
if type(accept) == "table" then
accept = accept[1]
end
accept = split(accept, ",")[1]
if not formats[accept] then
return status, body, headers
end
return formats[accept](status, get_message(status), headers)
end
Configure the exit-transformer
plugin with custom-errors-by-mimetype.lua
:
curl -X POST http://localhost:8001/services/example.com/plugins \
-F "name=exit-transformer" \
-F "config.handle_unknown=true" \
-F "config.handle_unexpected=true" \
-F "config.functions=@examples/custom-errors-by-mimetype.lua"