Merge pull request #25 from apimesh/pathParam

Path param
diff --git a/api-gateway-config/scripts/lua/lib/filemgmt.lua b/api-gateway-config/scripts/lua/lib/filemgmt.lua
index 95a506e..7c0ed03 100644
--- a/api-gateway-config/scripts/lua/lib/filemgmt.lua
+++ b/api-gateway-config/scripts/lua/lib/filemgmt.lua
@@ -35,16 +35,18 @@
 -- @param resourceObj object containing different operations/policies for the resource
 -- @return fileLocation location of created/updated conf file
 function _M.createResourceConf(baseConfDir, tenant, gatewayPath, resourceObj)
+  resourceObj = utils.serializeTable(cjson.decode(resourceObj))
   local decoded = cjson.decode(resourceObj)
-  resourceObj = utils.serializeTable(decoded)
+
   local prefix = utils.concatStrings({"\tinclude /etc/api-gateway/conf.d/commons/common-headers.conf;\n",
                                       "\tset $upstream https://172.17.0.1;\n",
                                       "\tset $tenant ", tenant, ";\n",
-                                      "\tset $gatewayPath ", gatewayPath, ";\n"})
+                                      "\tset $gatewayPath ",  utils.concatStrings({"\"", ngx.unescape_uri(gatewayPath),
+                                      "\""}), ";\n\n"})
   if decoded.apiId ~= nil then
     prefix = utils.concatStrings({prefix, "\tset $apiId ", decoded.apiId, ";\n"})
   end
-  -- Set route headers and mapping by calling routing.processCall()
+  -- Set resource headers and mapping by calling routing.processCall()
   local outgoingResource = utils.concatStrings({"\taccess_by_lua_block {\n",
                                                 "\t\tlocal routing = require \"routing\"\n",
                                                 "\t\trouting.processCall(", resourceObj, ")\n",
@@ -57,7 +59,10 @@
   if not file then
     request.err(500, utils.concatStrings({"Error adding to endpoint conf file: ", err}))
   end
-  local location = utils.concatStrings({"location /api/", tenant, "/", ngx.unescape_uri(gatewayPath), " {\n",
+
+  local updatedPath = ngx.unescape_uri(gatewayPath):gsub("%{(%w*)%}", utils.convertTemplatedPathParam)
+
+  local location = utils.concatStrings({"location ~ ^/api/", tenant, "/", updatedPath, " {\n",
                                         prefix,
                                         outgoingResource,
                                         "}\n"})
diff --git a/api-gateway-config/scripts/lua/lib/utils.lua b/api-gateway-config/scripts/lua/lib/utils.lua
index 1ed2897..a064037 100644
--- a/api-gateway-config/scripts/lua/lib/utils.lua
+++ b/api-gateway-config/scripts/lua/lib/utils.lua
@@ -22,6 +22,7 @@
 --
 -- @author Alex Song (songs), Cody Walker (cmwalker)
 
+local cjson = require "cjson"
 local _Utils = {}
 
 --- Concatenate a list of strings into a single string. This is more efficient than concatenating
@@ -65,7 +66,36 @@
   return table.concat(tt)
 end
 
+--- Concatenate the path param name into string variable to be replaced by the path param value
+-- at time of being called by the user
+-- @param m where m is the string "{pathParam}"
+-- @return concatenated string of (?<path_pathParam>(\\w+))
+function convertTemplatedPathParam(m)
+  local x = m:gsub("{", ""):gsub("}", "")
+  return concatStrings({"(?<path_" , x , ">([a-zA-Z0-9\\-\\s\\_\\%]*))"})
+end
+
+
+--- Convert JSON body to Lua table using the cjson module
+-- @param args Lua table with its key as the string representation of a JSON body
+-- @return Lua table representation of JSON
+function convertJSONBody(args)
+  local jsonStringList = {}
+  for key, value in pairs(args) do
+    table.insert(jsonStringList, key)
+    -- Handle case where the "=" character is inside any of the strings in the json body
+    if(value ~= true) then
+      table.insert(jsonStringList, concatStrings({"=", value}))
+    end
+  end
+  return cjson.decode(concatStrings(jsonStringList))
+end
+
+
+_Utils.convertJSONBody = convertJSONBody
 _Utils.concatStrings = concatStrings
 _Utils.serializeTable = serializeTable
+_Utils.convertTemplatedPathParam = convertTemplatedPathParam
 
 return _Utils
+
diff --git a/api-gateway-config/scripts/lua/management.lua b/api-gateway-config/scripts/lua/management.lua
index acb2a16..08b9276 100644
--- a/api-gateway-config/scripts/lua/management.lua
+++ b/api-gateway-config/scripts/lua/management.lua
@@ -60,7 +60,8 @@
     request.err(400, "Missing Request body")
   end
   -- Convert json into Lua table
-  local decoded = convertJSONBody(args)
+  local decoded = utils.convertJSONBody(args)
+
   -- Error handling for required fields in the request body
   local gatewayMethod = decoded.gatewayMethod
   if not gatewayMethod then
@@ -272,22 +273,8 @@
   if not list[1] or not list[2] then
     request.err(400, "Request path should be \"/resources/<tenant>/<url-encoded-resource>\"")
   end
-  return list --prefix, tenant, gatewayPath
-end
 
---- Convert JSON body to Lua table using the cjson module
--- @param args Lua table with its key as the string representation of a JSON body
--- @return Lua table representation of JSON
-function convertJSONBody(args)
-  local jsonStringList = {}
-  for key, value in pairs(args) do
-    table.insert(jsonStringList, key)
-    -- Handle case where the "=" character is inside any of the strings in the json body
-    if(value ~= true) then
-      table.insert(jsonStringList, utils.concatStrings({"=", value}))
-    end
-  end
-  return cjson.decode(utils.concatStrings(jsonStringList))
+  return list  --prefix, tenant, gatewayPath, apiKey
 end
 
 return _M
\ No newline at end of file
diff --git a/api-gateway-config/scripts/lua/policies/mapping.lua b/api-gateway-config/scripts/lua/policies/mapping.lua
index 9272c63..0ad97e3 100644
--- a/api-gateway-config/scripts/lua/policies/mapping.lua
+++ b/api-gateway-config/scripts/lua/policies/mapping.lua
@@ -24,12 +24,14 @@
 local logger = require "lib/logger"
 local utils = require "lib/utils"
 local cjson = require "cjson"
+local url = require "url"
 
 local _M = {}
 
 local body = nil
 local query = nil
 local headers = nil
+local path = nil
 
 --- Implementation for the mapping policy.
 -- @param map The mapping object that contains details about request tranformations
@@ -51,12 +53,14 @@
 
 --- Get request body, params, and headers from incoming requests
 function getRequestParams()
-  body =  ngx.req.get_body_data()
-  if body == nil then
-    body = {}
+  ngx.req.read_body()
+  body = ngx.req.get_post_args()
+  if next(body) then
+    body = utils.convertJSONBody(body)
   end
   query = ngx.req.get_uri_args()
-  headers = ngx.resp.get_headers()
+  headers = ngx.req.get_headers()
+  path = ngx.var.uri
 end
 
 --- Insert parameter value to header, body, or query params into request
@@ -72,6 +76,8 @@
     v = query[m.from.name]
   elseif m.from.location == 'body' then
     v = body[m.from.name]
+  elseif m.from.location == 'path' then
+    v = ngx.var[utils.concatStrings({'path_', m.from.name})]
   end
   -- determine to where
   if m.to.location == 'header' then
@@ -80,6 +86,8 @@
     insertQuery(k, v)
   elseif m.to.location == 'body' then
     insertBody(k, v)
+  elseif m.to.location == 'path' then
+    insertPath(k,v)
   end
 end
 
@@ -148,13 +156,24 @@
       insertParam(t)
       removeParam(t)
     end
+  elseif s == 'path' then
+    for k, v in pairs(path) do
+      local t = {}
+      t.from = {}
+      t.from.name = k
+      t.from.location = s
+      t.to = {}
+      t.to.name = k
+      t.to.location = d
+      insertParam(t)
+      removeParam(t)
+    end
   end
 end
 
 function finalize()
   local bodyJson = cjson.encode(body)
   ngx.req.set_body_data(bodyJson)
-  ngx.req.set_uri_args(query)
 end
 
 function insertHeader(k, v)
@@ -163,12 +182,19 @@
 
 function insertQuery(k, v)
   query[k] = v
+  ngx.req.set_uri_args(query)
 end
 
 function insertBody(k, v)
   body[k] = v
 end
 
+function insertPath(k, v)
+  v = ngx.unescape_uri(v)
+  local primedUri = path:gsub("%{(%w*)%}", v)
+  ngx.req.set_uri(primedUri)
+end
+
 function removeHeader(k)
   ngx.req.clear_header(k)
 end