Background#
When accessing APIs via Kong Gateway, you may want to be notified if a request fails. The usual approach is to save logs with a logging plugin and then set up alerts and notifications using a third-party product (like ELK). However, using other products can be cumbersome to deploy, require licenses and extra configuration, and ideally, you’d like to achieve this within Kong itself. In this article, I’ll show how to use the Exit Transformer
plugin to trigger a Slack Webhook via Lua script when a request results in an error. This plugin allows you to transform and customize Kong’s response messages using Lua functions. You can change the message, status code, headers, or even completely transform the response structure.
Trying the Plugin#
Let’s start by trying the example from the documentation.
Create Service and Route#
1
2
| http :8001/services name=example.com host=mockbin.org
http -f :8001/services/example.com/routes hosts=example.com
|
Add key-auth Plugin to Force Failure#
1
| http :8001/services/example.com/plugins name=key-auth
|
Create Lua Script#
The following code adds the header x-some-header
and appends , arr
to the end of the message. Save this as transform.lua
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| -- 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
|
Deploy the Plugin with the Script#
1
2
3
| http -f :8001/services/example.com/plugins \
name=exit-transformer \
config.functions=@transform.lua
|
Test#
After setting up, try accessing the service. The header and the arr
message should be added to the response.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| ❯ http :8000 Host:example.com
HTTP/1.1 401 Unauthorized
Connection: keep-alive
Content-Length: 73
Content-Type: application/json; charset=utf-8
Date: Fri, 10 Feb 2023 07:36:15 GMT
Server: kong/3.1.1.3-enterprise-edition
WWW-Authenticate: Key realm="kong"
X-Kong-Response-Latency: 2
x-some-header: some value
{
"error": true,
"message": "No API key found in request, arr!",
"status": 401
}
|
Implementing Webhook in the Script#
This time, we’ll use Slack’s Webhook. After adding content to the message, the script will trigger the webhook.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| ...
local httpc = require("resty.http").new()
-- Single-shot requests use the `request_uri` interface.
local res, err = httpc:request_uri("https://hooks.slack.com/services/xxxxxx/xxxxxx/xxxxxxxx", {
method = "POST",
body = '{"text": "Hello, world."}',
headers = {
["Content-Type"] = "application/json",
},
})
if not res then
ngx.log(ngx.ERR, "request failed: ", err)
return
end
return status, new_body, headers
...
|
To send the request, we use lua-resty-http. Normally, you use require
to make the request, but there is a concern that it may not work well with the nginx event loop. That is, while waiting for a response from hooks.slack.com, nginx may not be able to process other requests.
Another thing to note is that since an external library is being called, you need to set the untrusted_lua parameter to On. Otherwise, you’ll get an error like this:
1
| 2023/02/10 02:19:13 [error] 2175#0: *15812 lua entry thread aborted: runtime error: /usr/local/share/lua/5.1/kong/tools/sandbox.lua:88: require 'ssl.https' not allowed within sandbox
|
Test Again#
Now, access the API again and check the Slack message!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| ❯ http :8000 Host:example.com
HTTP/1.1 401 Unauthorized
Connection: keep-alive
Content-Length: 73
Content-Type: application/json; charset=utf-8
Date: Mon, 13 Feb 2023 13:28:42 GMT
Server: kong/3.1.1.3-enterprise-edition
WWW-Authenticate: Key realm="kong"
X-Kong-Response-Latency: 0
x-some-header: some value
{
"error": true,
"message": "No API key found in request, arr!",
"status": 401
}
|

It worked!!