News KrakenD CE v2.6 released with OpenTelemetry

Enterprise Documentation

Recent changes

Dynamic Routing

Document updated on Feb 21, 2023

Dynamic Routing

The dynamic routing extends the routing capabilities to add header and query string processing to assemble the final upstream URL you want to reach. In addition, it allows you to convert headers to query strings and enforce the existence of parameters on the request.

To enable dynamic routing, you don’t need to add any specific extra entry in the configuration. Instead, write directly in the url_pattern the variables that inject the content provided by the user. For instance:

{
  "endpoint": "/foo",
  "backend":[
    {
      "url_pattern": "/{input_headers.X-Tenant}/foo"
    }
  ]
}

The example above replaces the variable {input_headers.X-Tenant} with the value provided under a hypothetical X-Tenant header.

Dynamic routing declaration

There are three different types of input injections you can do in the backend URL, available with the following variables:

  • input_headers: Header routing
  • input_query_strings: Query string routing
  • JWT: JWT-claim routing

To declare dynamic routes based on the strategies above, you need to write the variables inside curly braces {} and traverse the objects using a dot . separator, including the index of arrays.

Missing parameters?
When the user does not pass a required input header or query string, the gateway raises an error 400 Bad Request, as the final URL can’t be generated. Missing JWT claims will pass the request, but you can enforce them with security policies

Routing based on headers

The most typical scenario for dynamic routing is when you want to reach a service based on an input header. To access header values, use the above-defined variable {input_headers.}.

As the dynamic routing component executes before the endpoint evaluation, you don’t need to add the accessed values under input_headers unless you want these headers propagated to the backend.

For instance, let’s say that you want to pass a customer identifier as a header and use it in a URL containing it:

{
  "endpoints": [
    {
      "endpoint": "/user/{id}",
      "backend": [{
        "url_pattern": "/{input_headers.customer}/user/{id}"
      }]
    }
  ]
}

With a configuration like the above, the user would pass the customer information in the header, for instance:

Using routing based on headers 
$curl -H'Customer: abcdef' http://krakend/user/1234

The upstream service receives /abcdef/user/1234.

When multiple entries of the same header exist, you can specify the index of which one is in the variable. For instance, with /foo/{input_headers.customer.1}, the backend would receive the second value of the header (indexes are zero-based). Not specifying an index always defaults to the first element of an array, so {input_headers.customer} and {input_headers.customer.0} both return the same value.

In addition, you can do header validation and other sophisticated checks using the security policies component. For instance, you could make sure that the header adheres to a specific format expressed by a regex:

{
  "endpoints": [
    {
      "endpoint": "/user/{id}",
      "backend": [
        {
          "url_pattern": "/{input_headers.customer}/user/{id_user}"
        }
      ],
      "extra_config": {
        "security/policies": {
          "req": {
            "policies": [
              "getHeader('Customer').matches('^/[a-z]{4}$')"
            ],
            "error": {
              "body": "Mailformed customer request",
              "status": 400
            }
          }
        }
      }
    }
  ]
}

Routing based on query strings

Similarly to headers, you can route a query string as a path following the same strategy. If you want to forward the query string to the backend as is, you only need to add it under the input_query_strings list. If on the other side, you would like to convert a query string into a part of the path, then you can apply the variables as follows:

{
  "endpoints": [
    {
      "endpoint": "/user",
      "backend": [
        {
          "url_pattern": "/user/{input_query_strings.id_user}"
        }
      ]
    }
  ]
}

The example above takes a request /user?id_user=john and converts it to /user/john towards the backend.

When there are multiple entries of the exact query string, for instance, /foo?q=a&q=b, you can specify the index in the variable. For example, with /bar/{input_query_strings.q.1}, the backend would receive /bar/b (zero-based indexes). Not specifying an index always defaults to the first element of an array, so {input_query_strings.q} and {input_query_strings.q.0} both evaluate to /bar/a.

As the dynamic routing component executes before the endpoint evaluation, you don’t need to add the accessed values under input_query_strings unless you want the query strings sent twice to the backend.

Routing based on a JWT claim

You can inject claims to the backend’s final URL if you are using the JWT validator in the same endpoint through the {JWT.} variable. For instance, you could declare a url_pattern making use of {JWT.sub}, where sub is a first-level claim of your JWT payload (you cannot traverse nested claims).

For instance, when your JWT payload is represented by something like this:

{
    "sub": "1234567890",
    "name": "Mr. KrakenD"
}

Then, when you use an "url_pattern": "/foo/{JWT.sub}", it translates into /foo/1234567890.

If KrakenD can’t replace the claim’s content for any reason, the backend receives a request to the literal URL /foo/{JWT.sub}, unlike the 400 error of the previous two variables.

Conversion of headers to query strings

You don’t need to use the variables in the url_pattern as part of the path, and you can use them freely as long you form a valid url_pattern. Yet, it is especially relevant when passing a header as a query string, where you would use the variable as a query string, not a path. E.g., "url_pattern": "/foo?query={input_headers.query}". Any additional query strings you allow to pass using the input_headers list are appended to the URL pattern.

Scarf

Unresolved issues?

The documentation is only a piece of the help you can get! Whether you are looking for Open Source or Enterprise support, see more support channels that can help you.

We use cookies to understand how you use our site and to improve your overall experience. By continuing to use our site, you accept our Privacy Policy. More information