Refactor management interface error handling
diff --git a/api-gateway-config/scripts/lua/management.lua b/api-gateway-config/scripts/lua/management.lua
index 05cb3d3..a720883 100644
--- a/api-gateway-config/scripts/lua/management.lua
+++ b/api-gateway-config/scripts/lua/management.lua
@@ -133,63 +133,95 @@
return false, { statusCode = 404, message = utils.concatStrings({"Unknown tenant id ", object }) }
end
end
- -- Additional checks for resource object
if field == "resources" then
- local resources = object
- if next(object) == nil then
- return false, { statusCode = 400, message = "Empty resources object." }
- end
- for path, resource in pairs(resources) do
- -- Check resource path for illegal characters
- if string.match(path, "'") then
- return false, { statusCode = 400, message = "resource path contains illegal character \"'\"." }
- end
- -- Check that resource path begins with slash
- if path:sub(1,1) ~= '/' then
- return false, { statusCode = 400, message = "Resource path must begin with '/'." }
- end
- -- Check operations object
- if not resource.operations or next(resource.operations) == nil then
- return false, { statusCode = 400, message = "Missing or empty field 'operations' or in resource path object." }
- end
- for verb, verbObj in pairs(resource.operations) do
- local allowedVerbs = {GET=true, POST=true, PUT=true, DELETE=true, PATCH=true, HEAD=true, OPTIONS=true}
- if allowedVerbs[verb:upper()] == nil then
- return false, { statusCode = 400, message = utils.concatStrings({"Resource verb '", verb, "' not supported."}) }
- end
- -- Check required fields
- local requiredFields = {"backendMethod", "backendUrl"}
- for k, v in pairs(requiredFields) do
- if verbObj[v] == nil then
- return false, { statusCode = 400, message = utils.concatStrings({"Missing field '", v, "' for '", verb, "' operation."}) }
- end
- if v == "backendMethod" then
- local backendMethod = verbObj[v]
- if allowedVerbs[backendMethod:upper()] == nil then
- return false, { statusCode = 400, message = utils.concatStrings({"backendMethod '", backendMethod, "' not supported."}) }
- end
- end
- end
- -- Check optional fields
- local policies = verbObj.policies
- if policies then
- for k, v in pairs(policies) do
- if v.type == nil then
- return false, { statusCode = 400, message = "Missing field 'type' in policy object." }
- end
- end
- end
- local security = verbObj.security
- if security and security.type == nil then
- return false, { statusCode = 400, message = "Missing field 'type' in security object." }
- end
- end
+ local res, err = checkResources(object)
+ if res ~= nil and res == false then
+ return res, err
end
end
-- All error checks passed
return true
end
+--- Error checking for resources
+-- @param resources resources object
+function checkResources(resources)
+ if next(resources) == nil then
+ return false, { statusCode = 400, message = "Empty resources object." }
+ end
+ for path, resource in pairs(resources) do
+ -- Check resource path for illegal characters
+ if string.match(path, "'") then
+ return false, { statusCode = 400, message = "resource path contains illegal character \"'\"." }
+ end
+ -- Check that resource path begins with slash
+ if path:sub(1,1) ~= '/' then
+ return false, { statusCode = 400, message = "Resource path must begin with '/'." }
+ end
+ -- Check operations object
+ local res, err = checkOperations(resource.operations)
+ if res ~= nil and res == false then
+ return res, err
+ end
+ end
+end
+
+--- Error checking for operations
+-- @param operations operations object
+function checkOperations(operations)
+ if not operations or next(operations) == nil then
+ return false, { statusCode = 400, message = "Missing or empty field 'operations' or in resource path object." }
+ end
+ local allowedVerbs = {GET=true, POST=true, PUT=true, DELETE=true, PATCH=true, HEAD=true, OPTIONS=true}
+ for verb, verbObj in pairs(operations) do
+ if allowedVerbs[verb:upper()] == nil then
+ return false, { statusCode = 400, message = utils.concatStrings({"Resource verb '", verb, "' not supported."}) }
+ end
+ -- Check required fields
+ local requiredFields = {"backendMethod", "backendUrl"}
+ for k, v in pairs(requiredFields) do
+ if verbObj[v] == nil then
+ return false, { statusCode = 400, message = utils.concatStrings({"Missing field '", v, "' for '", verb, "' operation."}) }
+ end
+ if v == "backendMethod" then
+ local backendMethod = verbObj[v]
+ if allowedVerbs[backendMethod:upper()] == nil then
+ return false, { statusCode = 400, message = utils.concatStrings({"backendMethod '", backendMethod, "' not supported."}) }
+ end
+ end
+ end
+ -- Check optional fields
+ local res, err = checkOptionalPolicies(verbObj.policies, verbObj.security)
+ if res ~= nil and res == false then
+ return res, err
+ end
+ end
+end
+
+--- Error checking for policies and security
+-- @param policies policies object
+-- @param security security object
+function checkOptionalPolicies(policies, security)
+ if policies then
+ for k, v in pairs(policies) do
+ local validTypes = {reqMapping = true, rateLimit = true}
+ if (v.type == nil or v.value == nil) then
+ return false, { statusCode = 400, message = "Missing field in policy object. Need \"type\" and \"scope\"." }
+ elseif validTypes[v.type] == nil then
+ return false, { statusCode = 400, message = "Invalid type in policy object. Valid: \"reqMapping\", \"rateLimit\"" }
+ end
+ end
+ end
+ if security then
+ local validScopes = {tenant=true, api=true, resource=true}
+ if (security.type == nil or security.scope == nil) then
+ return false, { statusCode = 400, message = "Missing field in security object. Need \"type\" and \"scope\"." }
+ elseif validScopes[security.scope] == nil then
+ return false, { statusCode = 400, message = "Invalid scope in security object. Valid: \"tenant\", \"api\", \"resource\"." }
+ end
+ end
+end
+
--- Helper function for adding a resource to redis and creating an nginx conf file
-- @param red
-- @param resource
@@ -518,9 +550,9 @@
-- {
-- key: *(String) key for tenant/api/resource
-- scope: *(String) tenant or api or resource
--- tenant: *(String) tenant id
+-- tenantId: *(String) tenant id
-- resource: (String) url-encoded resource path
--- api: (String) api id
+-- apiId: (String) api id
-- }
function _M.addSubscription()
-- Validate body and create redisKey
@@ -539,9 +571,9 @@
-- {
-- key: *(String) key for tenant/api/resource
-- scope: *(String) tenant or api or resource
--- tenant: *(String) tenant id
+-- tenantId: *(String) tenant id
-- resource: (String) url-encoded resource path
--- api: (String) api id
+-- apiId: (String) api id
-- }
function _M.deleteSubscription()
-- Validate body and create redisKey
@@ -560,19 +592,14 @@
function validateSubscriptionBody()
-- Read in the PUT JSON Body
ngx.req.read_body()
- local args = ngx.req.get_post_args()
+ local args = ngx.req.get_body_data()
if not args then
request.err(400, "Missing request body.")
end
-- Convert json into Lua table
- local decoded
- if next(args) then
- decoded = utils.convertJSONBody(args)
- else
- request.err(400, "Request body required.")
- end
+ local decoded = cjson.decode(args)
-- Check required fields
- local requiredFieldList = {"key", "scope", "tenant"}
+ local requiredFieldList = {"key", "scope", "tenantId"}
for i, field in ipairs(requiredFieldList) do
if not decoded[field] then
request.err(400, utils.concatStrings({"\"", field, "\" missing from request body."}))
@@ -582,7 +609,7 @@
local resource = decoded.resource
local apiId = decoded.apiId
local redisKey
- local prefix = utils.concatStrings({"subscriptions:tenant:", decoded.tenant})
+ local prefix = utils.concatStrings({"subscriptions:tenant:", decoded.tenantId})
if decoded.scope == "tenant" then
redisKey = prefix
elseif decoded.scope == "resource" then
diff --git a/doc/routes.md b/doc/routes.md
index 33887d0..dc9a2a5 100644
--- a/doc/routes.md
+++ b/doc/routes.md
@@ -245,9 +245,9 @@
{
"key": *(string) The api key to store to redis.
"scope": *(string) The scope to use the api key. "tenant", "resource", or "api".
- "tenant": *(string) Tenant guid.
+ "tenantId": *(string) Tenant guid.
"resource": (string) Resource path. Required if scope is "resource".
- "api": (string) API Guid. Required if scope is "API".
+ "apiId": (string) API Guid. Required if scope is "API".
}
```
@@ -264,9 +264,9 @@
{
"key": *(string) The api key to delete.
"scope": *(string) The scope to use the api key. "tenant", "resource", or "api".
- "tenant": *(string) Tenant guid.
+ "tenantId": *(string) Tenant guid.
"resource": (string) Resource path. Required if scope is "resource".
- "api": (string) API Guid. Required if scope is "API".
+ "apiId": (string) API Guid. Required if scope is "API".
}
```