Method transform not working together with url rewrite

Example API definition:

{
    "id": "5acef8b77233750001c9c156",
    "name": "bugtest",
    "slug": "bugtest",
    "api_id": "5d2435d561b249a240a467931ba25793",
    "org_id": "5aaad417a00472000162a9cc",
    "use_keyless": true,
    "use_oauth2": false,
    "use_openid": false,
    "openid_options": {
        "providers": [],
        "segregate_by_client": false
    },
    "oauth_meta": {
        "allowed_access_types": [],
        "allowed_authorize_types": [],
        "auth_login_redirect": ""
    },
    "auth": {
        "use_param": false,
        "param_name": "",
        "use_cookie": false,
        "cookie_name": "",
        "auth_header_name": "",
        "use_certificate": false
    },
    "use_basic_auth": false,
    "use_mutual_tls_auth": false,
    "client_certificates": [],
    "upstream_certificates": {},
    "pinned_public_keys": {},
    "enable_jwt": false,
    "use_standard_auth": false,
    "enable_coprocess_auth": false,
    "jwt_signing_method": "",
    "jwt_source": "",
    "jwt_identity_base_field": "",
    "jwt_client_base_field": "",
    "jwt_policy_field_name": "",
    "notifications": {
        "shared_secret": "",
        "oauth_on_keychange_url": ""
    },
    "enable_signature_checking": false,
    "hmac_allowed_clock_skew": -1,
    "base_identity_provided_by": "",
    "definition": {
        "location": "url",
        "key": "x-api-version"
    },
    "version_data": {
        "not_versioned": true,
        "default_version": "",
        "versions": {
            "Default": {
                "name": "Default",
                "expires": "",
                "paths": {
                    "ignored": [],
                    "white_list": [],
                    "black_list": []
                },
                "use_extended_paths": true,
                "extended_paths": {
                    "url_rewrites": [
                        {
                            "path": "user",
                            "method": "GET",
                            "match_pattern": "user",
                            "rewrite_to": "http://httpbin.org/anything",
                            "triggers": [],
                            "MatchRegexp": null
                        }
                    ],
                    "method_transforms": [
                        {
                            "path": "user",
                            "method": "GET",
                            "to_method": "POST"
                        }
                    ]
                },
                "global_headers": {},
                "global_headers_remove": [],
                "global_size_limit": 0,
                "override_target": ""
            }
        }
    },
    "uptime_tests": {
        "check_list": [],
        "config": {
            "expire_utime_after": 0,
            "service_discovery": {
                "use_discovery_service": false,
                "query_endpoint": "",
                "use_nested_query": false,
                "parent_data_path": "",
                "data_path": "",
                "port_data_path": "",
                "target_path": "",
                "use_target_list": false,
                "cache_timeout": 60,
                "endpoint_returns_list": false
            },
            "recheck_wait": 0
        }
    },
    "proxy": {
        "preserve_host_header": false,
        "listen_path": "/5d2435d561b249a240a467931ba25793/",
        "target_url": "http://httpbin.org",
        "strip_listen_path": true,
        "enable_load_balancing": false,
        "target_list": [],
        "check_host_against_uptime_tests": false,
        "service_discovery": {
            "use_discovery_service": false,
            "query_endpoint": "",
            "use_nested_query": false,
            "parent_data_path": "",
            "data_path": "",
            "port_data_path": "",
            "target_path": "",
            "use_target_list": false,
            "cache_timeout": 0,
            "endpoint_returns_list": false
        }
    },
    "disable_rate_limit": false,
    "disable_quota": false,
    "custom_middleware": {
        "pre": [],
        "post": [],
        "post_key_auth": [],
        "auth_check": {
            "name": "",
            "path": "",
            "require_session": false
        },
        "response": [],
        "driver": "",
        "id_extractor": {
            "extract_from": "",
            "extract_with": "",
            "extractor_config": {}
        }
    },
    "custom_middleware_bundle": "",
    "cache_options": {
        "cache_timeout": 60,
        "enable_cache": false,
        "cache_all_safe_requests": false,
        "cache_response_codes": [],
        "enable_upstream_cache_control": false,
        "cache_control_ttl_header": ""
    },
    "session_lifetime": 0,
    "active": true,
    "auth_provider": {
        "name": "",
        "storage_engine": "",
        "meta": {}
    },
    "session_provider": {
        "name": "",
        "storage_engine": "",
        "meta": {}
    },
    "event_handlers": {
        "events": {}
    },
    "enable_batch_request_support": false,
    "enable_ip_whitelisting": false,
    "allowed_ips": [],
    "enable_ip_blacklisting": false,
    "blacklisted_ips": [],
    "dont_set_quota_on_create": false,
    "expire_analytics_after": 0,
    "response_processors": [
        {
            "name": "response_body_transform",
            "options": {}
        }
    ],
    "CORS": {
        "enable": true,
        "allowed_origins": [
            "https://scrip.tk"
        ],
        "allowed_methods": [],
        "allowed_headers": [],
        "exposed_headers": [],
        "allow_credentials": false,
        "max_age": 0,
        "options_passthrough": false,
        "debug": false
    },
    "domain": "",
    "do_not_track": false,
    "tags": [],
    "enable_context_vars": true,
    "config_data": {},
    "tag_headers": [],
    "global_rate_limit": {
        "rate": 0,
        "per": 0
    },
    "strip_auth_data": false
}

A GET request do /bugtest/user should be transformed to a POST request, but it doesn’t:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", 
    "Accept-Encoding": "gzip, deflate, br", 
    "Accept-Language": "en-US,en;q=0.9,it-IT;q=0.8,it;q=0.7,es;q=0.6", 
    "Cache-Control": "no-cache", 
    "Connection": "close", 
    "Dnt": "1", 
    "Host": "httpbin.org", 
    "Pragma": "no-cache", 
    "Upgrade-Insecure-Requests": "1", 
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 
    "X-Scheme": "https"
  }, 
  "json": null, 
  "method": "GET", 
  "origin": "185.183.105.27, 185.183.105.27, 172.30.2.233, 172.30.2.75, 54.84.218.129", 
  "url": "http://httpbin.org/anything"
}

I’m using Tyk Cloud.

You will need to apply the method transform middleware to the rewritten endpoint, i.e. “/anything” due to the middleware order of execution: //tyk.io/docs/plugins/supported-languages/javascript-middleware/

I can confirm that this is working on Cloud, let me know if you have any other questions :slight_smile:
-Luan

Thank you Luan, I missed that document.

Middlewares need tyk hybrid and I’m currently with the cloud version only.

I found a (not very efficient) workaround by changing the API target url to the api url and it works:

a GET request to https://api.cloud.tyk.io/test/simple now becomes a POST request to the same url where the url is rewritten to a new one.

But I’m now stack with the following:

if the POST endpoint has a response body transform, the response is not parsed as expected.

It works properly when called directly using a POST request but it returns <no value> when called through the GET request (and it should no I guess, since it should only proxy the response):

You can test with:

POST to https://api.cloud.tyk.io/test/trans (that works)
GET to https://api.cloud.tyk.io/test/trans (that miss the response transformation)

I also tried to apply the response body transform to the GET endpoint instead of the POST endpoint but the result is the same.

As a side note, request body transformation are working as expected.

The API definition:

{
  "api_definition": {
    "api_id": "5657fd955efb4e1344ae4945edbc4584",
    "upstream_certificates": {},
    "use_keyless": true,
    "enable_coprocess_auth": false,
    "custom_middleware": {
      "pre": [],
      "post": [],
      "post_key_auth": [],
      "auth_check": {
        "name": "",
        "path": "",
        "require_session": false
      },
      "response": [],
      "driver": "",
      "id_extractor": {
        "extract_from": "",
        "extract_with": "",
        "extractor_config": {}
      }
    },
    "disable_quota": false,
    "custom_middleware_bundle": "",
    "cache_options": {
      "enable_cache": true,
      "enable_upstream_cache_control": false,
      "cache_timeout": 60,
      "cache_response_codes": [],
      "cache_all_safe_requests": false
    },
    "enable_ip_blacklisting": false,
    "tag_headers": [],
    "pinned_public_keys": {},
    "domain": "",
    "openid_options": {
      "providers": [],
      "segregate_by_client": false
    },
    "active": true,
    "config_data": {},
    "notifications": {
      "oauth_on_keychange_url": "",
      "shared_secret": ""
    },
    "auth": {
      "auth_header_name": "",
      "use_certificate": false
    },
    "check_host_against_uptime_tests": false,
    "blacklisted_ips": [],
    "hmac_allowed_clock_skew": -1,
    "uptime_tests": {
      "check_list": [],
      "config": {
        "service_discovery": {
          "use_discovery_service": false,
          "query_endpoint": "",
          "use_nested_query": false,
          "parent_data_path": "",
          "data_path": "",
          "cache_timeout": 60
        }
      }
    },
    "enable_jwt": false,
    "name": "test",
    "slug": "test",
    "oauth_meta": {
      "allowed_access_types": [],
      "allowed_authorize_types": [],
      "auth_login_redirect": ""
    },
    "CORS": {
      "enable": false,
      "max_age": 24,
      "allow_credentials": false,
      "exposed_headers": [],
      "allowed_headers": [],
      "options_passthrough": false,
      "debug": false,
      "allowed_origins": [],
      "allowed_methods": []
    },
    "event_handlers": {
      "events": {}
    },
    "proxy": {
      "enable_load_balancing": false,
      "listen_path": "/5657fd955efb4e1344ae4945edbc4584/",
      "strip_listen_path": true,
      "preserve_host_header": false,
      "target_list": [],
      "target_url": "https://api.cloud.tyk.io/test",
      "service_discovery": {
        "cache_timeout": 0,
        "parent_data_path": "",
        "query_endpoint": "",
        "use_discovery_service": false,
        "_sd_show_port_path": false,
        "target_path": "",
        "use_nested_query": false,
        "data_path": "",
        "port_data_path": ""
      },
      "check_host_against_uptime_tests": false
    },
    "client_certificates": [],
    "use_basic_auth": false,
    "version_data": {
      "not_versioned": true,
      "versions": {
        "Default": {
          "name": "Default",
          "expires": "",
          "override_target": "",
          "extended_paths": {
            "url_rewrites": [
              {
                "method": "POST",
                "timeout": 0,
                "path": "simple",
                "add_headers": {},
                "samples": 100,
                "rewrite_to": "https://content-script.googleapis.com/v1/scripts/1hkrNVybpBVoNEdkscU4GuLspUftMns8luqe7xidQimoO1EmPk6XfSXBk:run?alt=json",
                "template_data": {
                  "input_type": "",
                  "template_mode": "",
                  "enable_session": false,
                  "template_source": ""
                },
                "function_source_uri": "",
                "threshold_percent": 0.1,
                "delete_headers": [],
                "response_function_name": "myVirtualHandler",
                "_lists": [],
                "match_pattern": "simple",
                "function_source_type": "blob",
                "triggers": [],
                "return_to_service_after": 60,
                "size_limit": 0,
                "use_session": false,
                "method_actions": {}
              }
            ],
            "method_transforms": [
              {
                "method": "GET",
                "timeout": 0,
                "path": "simple",
                "to_method": "POST",
                "add_headers": {},
                "samples": 100,
                "rewrite_to": "",
                "template_data": {
                  "input_type": "",
                  "template_mode": "",
                  "enable_session": false,
                  "template_source": ""
                },
                "function_source_uri": "",
                "threshold_percent": 0.1,
                "delete_headers": [],
                "response_function_name": "myVirtualHandler",
                "_lists": [],
                "match_pattern": "",
                "function_source_type": "blob",
                "return_to_service_after": 60,
                "size_limit": 0,
                "use_session": false,
                "method_actions": {}
              },
              {
                "method": "GET",
                "timeout": 0,
                "path": "trans",
                "to_method": "POST",
                "add_headers": {},
                "samples": 100,
                "rewrite_to": "",
                "template_data": {
                  "input_type": "",
                  "template_mode": "",
                  "enable_session": false,
                  "template_source": ""
                },
                "function_source_uri": "",
                "threshold_percent": 0.1,
                "delete_headers": [],
                "response_function_name": "myVirtualHandler",
                "_lists": [],
                "match_pattern": "",
                "function_source_type": "blob",
                "return_to_service_after": 60,
                "size_limit": 0,
                "use_session": false,
                "method_actions": {}
              }
            ],
            "transform": [
              {
                "method": "POST",
                "timeout": 0,
                "path": "trans",
                "add_headers": {},
                "samples": 100,
                "rewrite_to": "",
                "template_data": {
                  "input_type": "json",
                  "template_mode": "blob",
                  "enable_session": false,
                  "template_source": "ewoiZnVuY3Rpb24iOiAiZ2V0VXNlckluZm8iLAoicGFyYW1ldGVycyI6W10sCiJkZXZNb2RlIjp7e3RlbXBsYXRlICJkZXZfbW9kZSIgLl90eWtfY29udGV4dC5yZXF1ZXN0X2RhdGEuZGV2TW9kZX19Cn0KCnt7LSBkZWZpbmUgImRldl9tb2RlIiAtfX0KICB7ey0gaWYgLiAtfX0KICAgIHt7LSBpbmRleCAuIDAgLX19CiAge3stIGVsc2UgLX19CiAgICBmYWxzZQogIHt7LSBlbmQgLX19Cnt7LSBlbmQgLX19",
                  "input": "",
                  "output": ""
                },
                "function_source_uri": "",
                "threshold_percent": 0.1,
                "delete_headers": [],
                "response_function_name": "myVirtualHandler",
                "_lists": [],
                "match_pattern": "",
                "function_source_type": "blob",
                "return_to_service_after": 60,
                "size_limit": 0,
                "use_session": false,
                "method_actions": {}
              }
            ],
            "transform_response": [
              {
                "method": "POST",
                "timeout": 0,
                "path": "trans",
                "add_headers": {},
                "samples": 100,
                "rewrite_to": "",
                "template_data": {
                  "input_type": "json",
                  "template_mode": "blob",
                  "enable_session": false,
                  "template_source": "e3stIGlmIC5lcnJvciAtfX0KICAibXNnIjoie3stIC5lcnJvci5tZXNzYWdlIC19fSIKe3stIGVsc2UgLX19CiAge3stIC5yZXNwb25zZS5yZXN1bHQgLX19Cnt7LSBlbmQgLX19",
                  "input": "",
                  "output": ""
                },
                "function_source_uri": "",
                "threshold_percent": 0.1,
                "delete_headers": [],
                "response_function_name": "myVirtualHandler",
                "_lists": [],
                "match_pattern": "",
                "function_source_type": "blob",
                "return_to_service_after": 60,
                "size_limit": 0,
                "use_session": false,
                "method_actions": {}
              }
            ]
          },
          "global_headers": {
            "Accept": "application/json",
            "Content-Type": "application/json"
          },
          "global_headers_remove": [],
          "global_size_limit": 0,
          "use_extended_paths": true
        }
      },
      "default_version": ""
    },
    "use_standard_auth": false,
    "disable_rate_limit": false,
    "definition": {
      "key": "x-api-version",
      "location": "header"
    },
    "use_oauth2": false,
    "allowed_ips": [],
    "org_id": "5aaad417a00472000162a9cc",
    "enable_ip_whitelisting": false,
    "global_rate_limit": {
      "rate": 0,
      "per": 0
    },
    "enable_context_vars": false,
    "tags": [],
    "strip_auth_data": false,
    "id": "5acfad4e8f7915000152de48",
    "enable_signature_checking": false,
    "use_openid": false,
    "enable_batch_request_support": false,
    "response_processors": [
      {
        "name": "response_body_transform",
        "options": {}
      }
    ],
    "use_mutual_tls_auth": false,
    "auth_provider": {
      "name": "",
      "storage_engine": "",
      "meta": {}
    },
    "do_not_track": false,
    "dont_set_quota_on_create": false,
    "expire_analytics_after": 0,
    "session_lifetime": 0
  },
  "hook_references": [],
  "is_site": false,
  "sort_by": 0
}

The current go template for the response body transform is:

{{- if .error -}}
  "msg":"{{- .error.message -}}"
{{- else -}}
  {{- .response.result -}}
{{- end -}}

But you get the same problem also with a simpler one like:

{{ .error.message }}