How do I change the target_url for my proxy in a Custom Go Plugin?

This works using the UI and an advanced trigger via URL Rewrite. But in my Go plugin, I want to change the target_url so that I can do header validation and process the request to one of multiple upstreams depending on the header value.

Eg. header “UserID: 1” should send the upstream to Service A
header “UserID: 2” should send the upstream to Service B

etc.

The example below will accomplish a target_url redirect based on header value, in a Go plugin.

func setUpstream(r *http.Request, upstream string) {
	apiDef := ctx.GetDefinition(r)
	apiDef.Proxy.EnableLoadBalancing = true
	apiDef.Proxy.StructuredTargetList = apidef.NewHostListFromList([]string{upstream})
}

func ChangeUpstreamURL(rw http.ResponseWriter, r *http.Request) {
	userHeader := r.Header.Get("UserID")

	if userHeader == "1" {
		setUpstream(r, "https://httpbingo.org")
	} else if userHeader == "2" {
		setUpstream(r, "https://httpbin.org")
	} else {
		setUpstream(r, "https://google.com")
	}
}

Firas this is giving me Deja Vu from our sync today

Haha totally! This can definitely do what you’re looking to accomplish and we can make it more sophisticated too. Lets chat! :slightly_smiling_face:

I’m trying not to spam the forums, but I am having issue building the Go plugin in the Go custom plugin tutorial because we don’t have a license. I tried to use the docker image the tutorial uses directly, but there are incompatibilities in versions of the tutorial .go file

Any tips?

Makes perfect sense - you will need a license key to stand up the Gateway in the Custom-Go-Plugin repo. You can self serve a license key here and run that environment directly via the MakeFile.

Please note that this solution will override the StructuredTargetList at the API definition level, which can result in race conditions. For example, a ManyToMany relationship when we return a different upstream for identical requests (i.e., based on a key).

Could you explain more on this?

Our tests shows the golang url rewrite thing works as expected.

  • the host is rewritten based on the logic of the plugin
  • the apidef is preserved. its not changed by the plugin

Hey everyone,

We are actually building this functionality into our gateway at this point and I am running into this issue

I am posting my plugin code, the config_data values, and the logs. If you call the endpoint with no header first, the TargetList is nil. When you call the API again with a header it sets the List, but then if you call again, the List calls the last value that was stored there

Okay maybe it’s not going to let me post it. It’s throwing a 403 when I reply

Where are you looking at this host change in the plugin? I only see the StructuredTargetList changing