How to refactor our plugins for 0.13.x?

Seems some documentation may need updating here:

I see it still referring to the old api DAO “uris” … seems the 1 to 1 api uris reference is now in the routes “paths” object?

So my simple question is this, I have code like -

if ngx.ctx.api.uris ~= nil then
  for index, value in ipairs(ngx.ctx.api.uris) do
    ...stuff here..

I also have one snippet calling upon

ngx.ctx.api.request_path

What is the best way to evaluate what is equivalent to these in the new 0.13.x model, by just looking through the docs and always assuming the ctx object(ngx.ctx.service / ngx.ctx.route) is 1 to 1 mapped with the admin api objects presented?

I assume

ngx.ctx.api.uris -> ngx.ctx.route.paths ???
ngx.ctx.api.request_path -> ???

Hopefully this topic can be a guide to others how to migrate their plugins as well.

Thanks,
-Jeremy

Hi there,

Plugins aren’t really supposed to use this, since none of it is stable nor documented. The Plugins SDK is scheduled for 0.14 and will bring support for a stable user-facing API to do these things properly.

In the meantime, expect maybe more breakages, but you can use the following context variables:

ngx.ctx.api.uris -> ngx.ctx.route.paths

Yes.

ngx.ctx.api.request_path -> ???

ngx.ctx.route.paths

Have you thought on relying on ngx.ctx.router_matches instead? Could more appropriate for what you are doing with it.

Again, none of this is guaranteed to be stable as of today.

1 Like

Thanks for the tips and insight, I saw yall had refactored most of your underlying plugins where there was a need to support routes and services so I figured I would begin trying to tackle similar situations in my small array of modified plugins. I had very few instances where the ngx.ctx.api was being referenced anyways so hopefully I am not being too much of a daredevil in using the ctx.routes now :slight_smile: .

Turns out ngx.ctx.api.request_path was nil in my debugging earlier today always so I believe that is just dead code. Commented that part out so basically the only other piece I had was fixing up to incorporate routes (because a service can’t stand alone as a proxy def by itself right? service = backend endpoint and some proxy config settings, route = the expose path of the proxy uri/host or whatever (in simple terms)

For the routes piece I just did this, you can see the original code above my added snippit now:

    if ngx.ctx.api.uris ~= nil then
        for index, value in ipairs(ngx.ctx.api.uris) do
            if pl_stringx.startswith(ngx.var.request_uri, value) then
                path_prefix = value
                break
            end
        end

        if pl_stringx.endswith(path_prefix, "/") then
            path_prefix = path_prefix:sub(1, path_prefix:len() - 1)
        end

    end
	
    --Support for 0.13.x routes/services--
    if ngx.ctx.route.paths ~= nil then
        for index, value in ipairs(ngx.ctx.route.paths) do
            if pl_stringx.startswith(ngx.var.request_uri, value) then
                path_prefix = value
                break
            end
        end

        if pl_stringx.endswith(path_prefix, "/") then
            path_prefix = path_prefix:sub(1, path_prefix:len() - 1)
        end

    end
-- END OF NEW SUPPORT CODE--

Never used that ngx.ctx.router_matches before, seems like it might be able to replace the fact I have to have dup code for api dao and route dao atm in this logic eh?

Looking forward to the public api, and all the benefit that can provide us kongers!

Thx,
Jeremy

It seems like router_matches will provide you with what you need, instead of having to loop over the attributes of the matched route like that.

1 Like

This is so much cleaner!!! Not sure if its possible for router_matches.uri to end in a “/” so I kept that but if it does not then this could get even smaller :+1: .

    if ngx.ctx.router_matches ~= nil then 
       path_prefix = ngx.ctx.router_matches.uri
       if pl_stringx.endswith(path_prefix, "/") then
          path_prefix = path_prefix:sub(1, path_prefix:len() - 1)
       end
    end

thibaultcha helping scrub community kong coders see the light :smile: Thanks, I think one of the hardest parts for us as dev’s is the fact these little gems are not well documented. But I suppose thats another goal of the public lua api work your team has begun.

btw, would you mind explaining what you are trying to do with that code snippet? It might be something we’d want to add support for maybe? ngx.ctx.router_matches.uri can be a regex, so watch out for that.

1 Like

Certainly can go into detail. Took a community plugin for oidc and made it work with ping federate and integrated it work with your awesome mlcache. Code looks like so to get a larger picture:

    local path_prefix = ""
	
    if ngx.ctx.router_matches ~= nil then 
       path_prefix = ngx.ctx.router_matches.uri
       if pl_stringx.endswith(path_prefix, "/") then
          path_prefix = path_prefix:sub(1, path_prefix:len() - 1)
	end
    end

    local callback_url = ngx.var.scheme .. "://" .. ngx.var.host .. path_prefix .. "/oauth2/callback"

    -- check if we are calling the callback endpoint
    if ngx.re.match(ngx.var.request_uri, string.format(OAUTH_CALLBACK, path_prefix)) then
        handle_callback(conf, callback_url)

Some of the nice cache logic we added

local function getUserInfo(access_token, callback_url, conf)
    local httpc = http:new()
    local res, err = httpc:request_uri(conf.user_url, {
        method = "GET",
        ssl_verify = false,
        headers = {
          ["Authorization"] = "Bearer " .. access_token,
        }
    })
	
  -- redirect to auth if user result is invalid not 200
  if res.status ~= 200 then
    return redirect_to_auth(conf, callback_url)
  end

  local userJson = cjson.decode(res.body)

  return userJson
end

local function getKongKey(eoauth_token, access_token, callback_url, conf)
  -- This will add a 60 second expiring TTL on this cached value
  -- https://github.com/thibaultcha/lua-resty-mlcache/blob/master/README.md
  local userInfo, err = singletons.cache:get(eoauth_token, { ttl = 60 }, getUserInfo, access_token, callback_url, conf)
	
  if err then
    ngx.log(ngx.ERR, "Could not retrieve UserInfo: ", err)
    return
  end

....................
             --Check boolean and then if EOAUTH has existing key -> userInfo value
            if conf.userInfoCacheEnabled then
                local userInfo = getKongKey(encrypted_token, access_token, callback_url, conf)
                if userInfo then
		  for i, key in ipairs(conf.user_keys) do
		      ngx.header["X-Oauth-".. key] = userInfo[key]
	    	      ngx.req.set_header("X-Oauth-".. key, userInfo[key])
		  end
		  ngx.header["X-Oauth-Token"] = access_token
		  if type(ngx.header["Set-Cookie"]) == "table" then
		      ngx.header["Set-Cookie"] = { "EOAuthUserInfo=0; Path=/;Max-Age=" .. conf.user_info_periodic_check .. ";HttpOnly", unpack(ngx.header["Set-Cookie"]) }
		  else
		      ngx.header["Set-Cookie"] = { "EOAuthUserInfo=0; Path=/;Max-Age=" .. conf.user_info_periodic_check .. ";HttpOnly", ngx.header["Set-Cookie"] }
		  end
					
		  return
                end
            end
            -- END OF NEW CACHE LOGIC --

Hmmm so if ngx.ctx.router_matches.uri can be a regex rather than the literal context uri string did you have an alternative reference you would recommend? Its working great but then again my uri was “/oidc/test” thus far in testing :slight_smile: .

-Jeremy