nginxlua3scale

How can I manipulate the JSON body of a POST request using Nginx and Lua?


I am doing a proof of concept to demonstrate how we might implement 3scale in our stack. In one example I want to do some POST request body manipulation to create an API façade that maps what might be a legacy API format to a new internal one. Eg. change something like

{ "foo" : "bar" , "deprecated" : true }

into

{ "FOO" : "bar" }

The Lua module docs for content_by_lua, which seems like the appropriate method say

Do not use this directive and other content handler directives in the same location. For example, this directive and the proxy_pass directive should not be used in the same location.

My understanding is that the content_by_lua is a content handler like proxy_pass, only one of which can be used per location.

I don't think there's any way to remove proxy_pass as that's the basis of how the proxying works, so is it possible capture the request in a separate location, use content_by_lua, then pass to the location implementing proxy_pass or is there a different method like rewrite_by_lua which is more appropriate?


If it helps anyone else, I added the following function (my first bit of Lua) which removes the user_key parameter which 3scale requires for authorization but is invalid for our API if forwarded on:

function remove_user_key()
  ngx.req.read_body()
  -- log the original body so we can compare to the new one later
  local oldbody = ngx.req.get_body_data()
  log(oldbody)
  -- grab the POST parameters as a table
  local params = ngx.req.get_post_args()

  -- build up the new JSON string
  local newbody = "{"

   for k,v in pairs(params) do
     -- add all the params we want to keep
     if k ~= "user_key" then
        log("adding"..k.." as "..v)
        newbody = newbody..'"'..k..'":"'..v..'",'
     else 
        log("not adding user_key")
     end
   end
  --remove the last trailing comma before closing this off
  newbody = string.sub(newbody, 0, #newbody-1)
  newbody = newbody.."}"

  ngx.req.set_body_data(newbody)
  log(newbody)
end

if ngx.req.get_method() == "POST" then
  remove_user_key()
end

Solution

  • I will suggest you to use access_by_lua
    in nginx.conf

    location / {
                    #host and port to fastcgi server
                    default_type text/html;
                    set $URL "http://$http_host$request_uri";
                    access_by_lua_file /home/lua/cache.lua;
                    proxy_pass http://$target;
                    -------
                    ---------
    

    in cache.lua file you can do something like :

    if ngx.req.get_method() == "POST" then
        -- check if request method is POST 
        -- implement your logic 
        return
    end