How to configure Tyk to return HTTP 404 for unmatched routes

Hi there! I started using Tyk recently, and my use cases comprise of a number of rewrite rules. In a nutshell a typical configuration could look as follows:

{
  "name": "default-api",
  "api_id": "default-api",
  "org_id": "default-org",
  "proxy": {
    "listen_path": "/",
    "target_url": "",
    "strip_listen_path": false,
    "preserve_host_header": true,
    "disable_strip_slash": true
  },
  "version_data": {
    "not_versioned": true,
    "versions": {
      "Default": {
        "name": "Default",
        "use_extended_paths": true,
        "extended_paths": {
          "white_list": [],
          "url_rewrites": [
            {
              "path": "/api/v1/resource/([^/]+)/(\\?.*)?$",
              "method": "GET",
              "match_pattern": "/api/v1/resource/([^/]+)/(\\?.*)?$",
              "rewrite_to": "http://mockserver-1:1080/api/v1/resource/$1/$2"
            },
            {
              "path": "/api/v1/resource/(\\?.*)?$",
              "method": "GET",
              "match_pattern": "/api/v1/resource/(\\?.*)?$",
              "rewrite_to": "http://mockserver-2:1080/api/v1/resource/$1"
            }
          ]
        }
      }
    }
  },
  "use_keyless": true
}

When this configuration is applied, Tyk redirects requests from /api/v1/resource/ to mockserver-2 and /api/v1/resource/{id}/ to mockserver-1. However when an unmatched request is received, for which a rule could not be found, HTTP 500 error is returned with the following message:

{
    "error": "There was a problem proxying the request"
}

Is there an option to make Tyk return HTTP 404 error for unmatched requests?

Hi

Yep it’s easy to setup - in the target URL of the api definition, which is going to be what is used as the fallback, use looping (Looping) to internally redirect to a mock response that returns a 404 - or any kind of response you like for that matter!

1 Like

Thanks for the suggestion, Josh! I’ll try it out.

I tried to add a fallback API using the following configuraiton:

{
  "name": "fallback-api",
  "api_id": "fallback-api",
  "org_id": "default",
  "version_data": {
    "not_versioned": true,
    "versions": {
      "Default": {
        "name": "Default",
        "use_extended_paths": true,
        "extended_paths": {
          "white_list": [
            {
              "path": "/",
              "method_actions": {
                "GET": {
                  "action": "reply",
                  "code": 404,
                  "data": "not found"
                }
              }
            }
          ]
        }
      }
    }
  },
  "internal": true,
  "use_keyless": true,
  "proxy": {
    "listen_path": "/fallback/",
    "strip_listen_path": false,
    "preserve_host_header": true,
    "disable_strip_slash": true
  }
}

In the default-api config, which I posted in the first message, I set .proxy.listen_path property to tyk://fallback-api/fallback/. After spinning up Tyk again I ran a few requests against the new instance and received mock responses only. According to the running mockserver logs, Tyk didn’t even try to send requests for the matching rewrite rules. Do I overlook something?

What does your original API def now look like?

This is the API definition JSON:

{
  "name": "default-api",
  "api_id": "default-api",
  "org_id": "default-org",
  "proxy": {
    "listen_path": "/",
    "target_url": "tyk://fallback-api/fallback/",
    "strip_listen_path": false,
    "preserve_host_header": true,
    "disable_strip_slash": true
  },
  "version_data": {
    "not_versioned": true,
    "versions": {
      "Default": {
        "name": "Default",
        "use_extended_paths": true,
        "extended_paths": {
          "white_list": [],
          "url_rewrites": [
            {
              "path": "/api/v1/resource/([^/]+)/(\\?.*)?$",
              "method": "GET",
              "match_pattern": "/api/v1/resource/([^/]+)/(\\?.*)?$",
              "rewrite_to": "http://mockserver:1080/api/v1/resource/$1/$2",
              "triggers": []
            },
            {
              "path": "/api/v1/resource/(\\?.*)?$",
              "method": "GET",
              "match_pattern": "/api/v1/resource/(\\?.*)?$",
              "rewrite_to": "http://mockserver:1080/api/v1/resource/$1",
              "triggers": []
            }
          ]
        },
        "global_headers_remove": [],
        "transform_headers": []
      }
    }
  },
  "auth": null,
  "enable_batch_request_support": true,
  "use_keyless": true,
  "use_basic_auth": false,
  "enable_signature_checking": false,
  "hmac_allowed_algorithms": [],
  "hmac_allowed_clock_skew": 0,
  "use_oauth2": false,
  "use_openid": false,
  "openid_options": null,
  "policies": null
}

You’re almost there - just one small tweak.

In internal looping the listen path of the internal API becomes the host so you can drop that from the target URL and it becomes tyk://fallback-api/

1 Like

Unfortunately, that didn’t work :frowning_face: I still get the response from the mocked api when I make a request against /api/v1/resource/ endpoint. And no log entries appear in my mockserver console.

I tried this quickly and I think there is a bug where the looped listen path doesnt get reset.

Instead for now do a real HTTP request back to your gateway host on localhost instead and i’ll open a bug report after some more investigation.

1 Like

I see. Thanks for assistance!