Modify target_url based on request URL


#1

Hi,

We are using tyk multi-cloud setup at the moment but having some difficulties when trying to apply multi region scheme.
Current setup:

  • host1 === points to tyk gateway in europe ====> [tyk gateway]
  • host2 === points to tyk gateway in usa ===> [tyk gateway]

Both of these gateways are managed through tyk dashboard.
Lets assume we have an api with slug: ‘test-slug’ and 1 target URL: https://REGION.internal.zone

This is the issue: how we can modify target URL on a fly and replacing REGION with the region from request URL?
Potentially that could be done using JS middleware like this:
>var middleware = new TykJS.TykMiddleware.NewMiddleware({});
>
>middleware.NewProcessRequest(function(request, session, spec) {
> target_url = spec.target_url.replace(“REGION”, request.Headers[“REGION”]);
> return middleware.ReturnData({Request: request, TargetURL: targer_url});
>});

In order to modify target_url we need to adjust mw_js_plugin.go:

type VMReturnObject struct {
Request MiniRequestObject
SessionMeta map[string]string
Session user.SessionState
AuthValue string
TargetURL string // Added
}

func specToJson(spec *APISpec) string {
m := map[string]interface{}{
“OrgID”: spec.OrgID,
“APIID”: spec.APIID,
// For backwards compatibility within 2.x.
// TODO: simplify or refactor in 3.x or later.
“config_data”: spec.ConfigData,
"target_url": spec.Proxy.TargetURL, // Added
}
bs, err := json.Marshal(m)
if err != nil {
log.Error("Failed to encode configuration data: ", err)
return “”
}
return string(bs)
}

func (d *DynamicMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, s interface{}) (error, int) { // Modified
t1 := time.Now().UnixNano()
logger := d.Logger()


// Decode the return object
newRequestData := VMReturnObject{}
if err := json.Unmarshal([]byte(returnDataStr), &newRequestData); err != nil {
logger.WithError(err).Error("Failed to decode middleware request data on return from VM. Returned data: ", returnDataStr)
return nil, http.StatusOK
}
s.Proxy.TargetURL = newRequestData.TargetURL // Added


And of course tests also needs to be adjusted.

The question is: is it possible to make it work like we want just by modifying configuration or we need to prepare a pull request for this one?

Regards,
Serghei


#2

For what you trying to do it makes sense to use URL Rewrite plugin with some advanced triggers, so it will look like:

match: /(.*)
If header “Region” non empty: rewrite_to: https://$tyk_context.headers_REGION.internal.zone/$1

Does it makes sense?


#3

I will try that. But i think solution with middleware is more flexible