Consume external services in a custom plugin
Use the lua-resty-http and lua-cjson libraries to make HTTP requests and parse the JSON responses.
Prerequisites
Series Prerequisites
This page is part of the Get started with custom plugin development series.
Complete the previous page, Add a custom plugin configuration before completing this page.
Include HTTP and JSON support
Start by importing two new libraries to the handler.lua
file to enable
HTTP and JSON parsing support.
We’ll use the lua-resty-http library for HTTP client connectivity to the third-party service.
For JSON support, we’ll use the lua-cjson library.
Add the libraries to the top of handler.lua
:
local http = require("resty.http")
local cjson = require("cjson.safe")
Send third-party HTTP requests
The lua-resty-http
library provides a simple HTTP request
function (request_uri
) that we can use to reach out to our third-party service.
In this example, we’ll send a GET
request to the httpbin.org/anything API.
Add the following to the top of the MyPluginHandler:response
function inside the
handler.lua
module:
local httpc = http.new()
local res, err = httpc:request_uri("http://httpbin.konghq.com/anything", {
method = "GET",
})
If the request to the third-party service is successful, the res
variable will contain the response.
Handle response errors
The Kong Gateway Plugin Development Kit provides you with various functions to help you handle error conditions.
In this example, we’re processing responses from the upstream service and decorating the client response with values from the third-party service. If the request to the third-party service fails, we can terminate the response processing and return to the client with an error, or continue processing the response and not complete the custom header logic.
In this example, we’ll terminate the
response processing and return a 500
internal server error to the client.
Add the following to the MyPluginHandler:response
function, immediately
after the httpc:request_uri
call:
if err then
return kong.response.error(500,
"Error when trying to access third-party service: " .. err,
{ ["Content-Type"] = "text/html" })
end
After this step, the handler.lua
file looks like this:
local http = require("resty.http")
local cjson = require("cjson.safe")
local MyPluginHandler = {
PRIORITY = 1000,
VERSION = "0.0.1",
}
function MyPluginHandler:response(conf)
local httpc = http.new()
local res, err = httpc:request_uri("http://httpbin.konghq.com/anything", {
method = "GET",
})
if err then
return kong.response.error(500,
"Error when trying to access third-party service: " .. err,
{ ["Content-Type"] = "text/html" })
end
kong.response.set_header(conf.response_header_name, "response")
end
Process JSON data from third-party response
This third-party service returns a JSON object in the response body. We’ll parse and extract a single value from the JSON body.
- In your
handler.lua
file, use thedecode
function in thelua-cjson
library passing in theres.body
value received from therequest_uri
function. Add this to your file right below what you added in the previous step:local body_table, err = cjson.decode(res.body)
The
decode
function returns a tuple of values. The first value contains the result of a successful decoding and represents the JSON as a table containing the parsed data. If an error occurs, the second value will contain error information (ornil
on success). - Add the following to the
MyPluginHandler:response
function after the previous line to stop processing in case of an error:if err then return kong.response.error(500, "Error while decoding third-party service response: " .. err, { ["Content-Type"] = "text/html" }) end
- Update the following line after the error handling to set the value of the
url
field in the response as the header value instead ofresponse
:kong.response.set_header(conf.response_header_name, body_table.url)
After this step, the handler.lua
file looks like this:
local http = require("resty.http")
local cjson = require("cjson.safe")
local MyPluginHandler = {
PRIORITY = 1000,
VERSION = "0.0.1",
}
function MyPluginHandler:response(conf)
kong.log("response handler")
local httpc = http.new()
local res, err = httpc:request_uri("http://httpbin.konghq.com/anything", {
method = "GET",
})
if err then
return kong.response.error(500,
"Error when trying to access third-party service: " .. err,
{ ["Content-Type"] = "text/html" })
end
local body_table, err = cjson.decode(res.body)
if err then
return kong.response.error(500,
"Error when decoding third-party service response: " .. err,
{ ["Content-Type"] = "text/html" })
end
kong.response.set_header(conf.response_header_name, body_table.url)
end
return MyPluginHandler
Update the tests
At this stage, using the pongo run
command to execute the integration tests will result in errors.
The value of the header has changed from response
to http://httpbin.konghq.com/anything
.
- Update the expected header value in
spec/my-plugin/01-integration_spec.lua
:-- validate the value of that header assert.equal("http://httpbin.konghq.com/anything", header_value)
- Run the tests:
pongo run
Pongo should report a successful test run.
Note: This series provides examples to get you started. In a real plugin development scenario, you would want to build integration tests for third-party services by providing a test dependency using a mock service instead of making network calls to the actual third-party service used. Pongo supports test dependencies for this purpose. See the Pongo documentation for details on setting test dependencies.