Did you know that you can try this plugin without talking to anyone with a free trial of Kong Konnect? Get started in under 5 minutes.
Transform and customize Kong response exit messages using Lua functions. The capabilities range from changing messages, status codes, and headers, to completely transforming the structure of Kong responses.
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 should only be enabled on a single plugin configuration. - The
handle_unexpected
parameter can be enabled on as many plugin configurations as you want.
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)
kong.response.exit()
requires a status
argument only.
body
and headers
may be nil
.
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
Step 1: Create a Service in Kong
Step 2: Create a Route in Kong
Step 3: Create a Transform
Create a file named transform.lua
with the transformation code. The
following example adds a header, appends “arr!” to any message, and adds
error
and status
fields on the response body.
-- 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
Step 4: Configure the Plugin with its Transform
Configure the exit-transformer
plugin with transform.lua
.
Step 5: Configure the Key-Auth Plugin to Test the Exit Transform
Add the key-auth
plugin to test a forced generation of an exit transform
response in step 6:
Step 6: 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.
Response:
HTTP/1.1 200 OK
...
X-Some-Header: some value
{
"error": true,
"status": 401,
"kong_message": "No API key found in request, arr!"
}
More Examples
Apply the Plugin Globally to Handle Unknown Responses
The plugin can also be applied globally:
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
.