Redirect separately to two similar GET endpoints

So, I’ve got two GET endpoints on my server app:
GET /measurement?param=... (let’s call it find) and GET /measurement/<id>?param=... (let’s call it get)

and I created two config files in my Tyk project for them separately. For the find one:

...
"extended_paths": {
          "url_rewrites": [
            {
              "path": "read/all",
              "method": "GET",
              "match_pattern": "read/all",
              "rewrite_to": "measurement"
            }
          ]
        }
...
  "proxy": {
    "preserve_host_header": false,
    "listen_path": "/read/all",
    "target_url": "http://service-read:3030/",
    "strip_listen_path": false
  },

And for the get one:

...
"extended_paths": {
          "url_rewrites": [
            {
              "path": "read/",
              "method": "GET",
              "match_pattern": "read/",
              "rewrite_to": "measurement/"
            }
          ]
        }
...
  "proxy": {
    "preserve_host_header": false,
    "listen_path": "/read/",
    "target_url": "http://service-read:3030/",
    "strip_listen_path": false
  },

But no matter whether I request GET /read/all?param=... or GET /read/123?param I always hit the find endpoint. So, I am thinking that for the get endpoint configuration, I need to add something after the / slashes of each config property, that will signify that there is a URL param.

Any suggestions?

Can you share your Tyk log from when the gateway starts or hot reloads? It should list out the heirarchy of what it is listening for.

If you have two APIs, then read/all will be matched before read/

I would suggest that to debug, get rid of the rewrite, and instead point your app at httpbin (which echoes back the request metadata that it receives), and then use the header injector instead of the rewriter to make sure that the capture pattern is working.

Once you’re certain it;s not the initial path match failing, then transpose that same config to the rewriter. Since you are not really using the rewriter to transpose data from the URL into the new one, you could just use wide regexes like (.*) for the match pattern, because they are for extracting and moving data, they shouldn;t affect the match itself ass that’s already happened.

Another thing you could do is have a single API definition that listens on /read/`, Then have it rewrite like this:

"url_rewrites": [
        {
          "path": /all",
          "method": "GET",
          "match_pattern": "all",
          "rewrite_to": "measurement"
        },
        {
          "path": "{a}",
          "method": "GET",
          "match_pattern": "(.*)",
          "rewrite_to": "measurement/"
        }
 ]

We’re using a wildcard {a} for the second version to catch the root (read), and then the other match is explicit for /all. That might work too…

Hey @Martin, I did change the configuration to what you suggested. Now it looks like this:

...
"extended_paths": {
          "url_rewrites": [
            {
              "path": "{a}",
              "method": "GET",
              "match_pattern": "(.*)",
              "rewrite_to": "measurement/"
            },
            {
              "path": "/all",
              "method": "GET",
              "match_pattern": "all",
              "rewrite_to": "measurement"
            }
          ]
        }
...
"proxy": {
    "preserve_host_header": false,
    "listen_path": "/read/",
    "target_url": "http://service-read:3030/",
    "strip_listen_path": false
  },

But still always redirects to the find endpoint.

The following is logged in the console when I start up the gateway container:

gateway      | time="Dec 22 08:14:46" level=error msg="Couldn't unmarshal configuration"
gateway      | time="Dec 22 08:14:46" level=error msg="json: cannot unmarshal string into Go value of type int"
gateway      | time="Dec 22 08:14:46" level=info msg="Connection dropped, connecting.."
gateway      | time="Dec 22 08:14:46" level=info msg="Starting Poller"
gateway      | time="Dec 22 08:14:46" level=info msg="Setting up Server"
gateway      | time="Dec 22 08:14:46" level=info msg="--> Standard listener (http)"
gateway      | time="Dec 22 08:14:46" level=info msg="Loading API Specification from /opt/tyk-gateway/apps/read.json"
gateway      | time="Dec 22 08:14:46" level=info msg="Loading API Specification from /opt/tyk-gateway/apps/write.json"
gateway      | time="Dec 22 08:14:46" level=info msg="Detected 2 APIs"
gateway      | time="Dec 22 08:14:46" level=info msg="--> Loading API: ReadService GET endpoints"
gateway      | time="Dec 22 08:14:46" level=info msg="----> Tracking: (no host)"
gateway      | time="Dec 22 08:14:46" level=info msg="----> Checking security policy: Open"
gateway      | time="Dec 22 08:14:46" level=info msg="--> Loading API: WriteService POST endpoint"
gateway      | time="Dec 22 08:14:46" level=info msg="----> Tracking: (no host)"
gateway      | time="Dec 22 08:14:46" level=info msg="----> Checking security policy: Open"
gateway      | time="Dec 22 08:14:46" level=info msg="Loading uptime tests..."
gateway      | time="Dec 22 08:14:46" level=error msg="Couldn't load policy file: read policies: is a directory"
gateway      | time="Dec 22 08:14:46" level=info msg="Gateway started (v2.0.0.0)"
gateway      | time="Dec 22 08:14:46" level=info msg="--> Listening on port: 8080"
gateway      | time="Dec 22 08:15:03" level=info msg="/read/s98k?from=1482315679472"
gateway      | time="Dec 22 08:15:10" level=info msg="/read/all?from=1482246169477"
gateway      | time="Dec 22 08:15:17" level=info msg="/read/s98k?from=1482315679472"

The last three lines are logs of when I was making requests to the service, through the gateway.

Sorry for late reply.

Can I suggest upgrading to the latest version, we’re on 2.3 at the moment and there’s been loads of routing fixes.

Your rewrites are in the wrong order, the {a} will always match, try reversing them:

"extended_paths": {
          "url_rewrites": [
            {
              "path": "/all",
              "method": "GET",
              "match_pattern": "all",
              "rewrite_to": "measurement"
            },            
            {
              "path": "{a}",
              "method": "GET",
              "match_pattern": "(.*)",
              "rewrite_to": "measurement/"
            }
          ]
        }
...

I assumed you were using the dashboard, which sorts routes by length for you before they are saved, if you are using file based mode then you need to add it manually.