Our API gateway is going to be a simplified version of a production system to ensure it is easy to follow. Being OpenResty-based, it means it's easily extendible to suit your needs.
In our nginx.conf file (located in /usr/local/openresty/nginx/conf), add the following script:
location /proxy/ { rewrite /proxy/(.*) /$1 break; allow 127.0.0.1; deny all; proxy_pass $1; } location /api { default_type 'application/json'; access_by_lua_file apigateway/auth.lua; content_by_lua_file apigateway/route.lua; }
Unlike the previous recipes, where we added the details within a lua block directive, this time we've separated the code into individual files for ease of management. Within the nginx directory (within the main OpenResty directory), we've created an apigateway directory to store the files for ease of management. Here's the code for the auth.lua file:
local cjson = require "cjson.safe" local allowedkeys = {"abc123", "def456", "hij789"} local function badAuth() ngx.status = 401 ngx.say(cjson.encode({status="error",
errmessage="Authentication Failed"})) ngx.exit(401) end local function isAuthorised (key) for index, value in ipairs(allowedkeys) do if value == key then return true end end return false end local authKey = ngx.req.get_headers()["X-API-KEY"] if authKey == nil then badAuth() elseif not isAuthorised(authKey) then badAuth() end
Next, we'll create a file to store the routing application code, named route.lua:
local cjson = require "cjson.safe" local redis = require "resty.redis" local red = redis:new() local ok, err = red:connect("127.0.0.1", 6379) if not ok then ngx.say(cjson.encode({status="ok", errormessage=
"Failed to connect to the redis server, the error was: "..err})) ngx.exit(500) end local apiroute = red:get(ngx.var.uri) if apiroute == ngx.null then ngx.say(cjson.encode({status="error", errormessage=
"no service at this path"})) ngx.exit(404) end res = ngx.location.capture("/proxy/"..apiroute) if res then ngx.say(cjson.encode({status="ok", result=res.body})) else ngx.say(cjson.encode({status="error",
errormessage="service failed to return a result"})) ngx.exit(500) end
We can test the authentication by running a call with and without the X-API-KEY header. Without the header, we can either browse to the URL or use cURL to send a GET request to /api/v1, and it should display the following:
{"status":"error","errmessage":"Authentication Failed"}
Conversely, with the correct header set, we should see the expected result returned. To test this, we can run the following:
curl -H "X-API-KEY: abc123" http://openresty.nginxcookbook.com/api/v1/test
The returned value should be as follows:
{"status":"ok","result":"This is a simple test!\n"}