Header-based routing with the Azure Front Door Rules Engine
When Azure Front Door was first released, it allowed you to have one backend host route to a multitude of different services based on the routing path.
For example, api.carbonpapersales.com/customers could route to a bunch of app services running in .NET dealing with customer data, and api.carbonpapersales.com/products could point to app services running in node dealing with product data.
This is a simple diagram, but you get the idea.
But what if the URL path was not enough, and you wanted to route based on stuff in the headers? Like a header that returned region-specific products?
This is now possible with the Azure Front Door Rules Engine, where you can override the path routing based on request headers.
How
To achieve this, I started a simple Azure Function, that returns the name of an environment variable, I couldn’t even be bothered giving the function a decent name.
Then, I published the Function App to two separate Azure App Services, SampleApp1 and SampleApp2. In each of those, I added an Application Setting that is to be read when calling the function.
By this point, I can call either function from Postman, and get the AppName returned.
So now let’s set up Front Door. I’m not going to go into too much on the initial work, but this is a basic configuration.
Under Frontends/domains, I have the URL that will be called, not much to say there.
Under Backend pools, I have a single pool that points to both of my Function Apps.
In Routing rules, I have a single rule that connects the frontend to the backend pool. By leaving the defaults anything that calls the frontend domain will be redirected to one of the Function Apps in the Backend Pool.
This can be checked in Postman
I want to do a bit more than this, and add additional backend pools, each one just pointing to a single Function App. These have no functionality for now, as the routing rule points to the first pool only.
Now comes time for the Rules Engine. You can find this under Settings in the Front Door Blade on the Azure Portal.
Here you can have a bunch of rules engines, each with their own lists of rules. One engine can link to one routing rule at most, but you don’t need to link an engine to a routing rule.
I created a new Engine, and assigned the following rules
Lets break this down a little
Under the IF condition, I check for a request header labelled “x-preferred-backend”, and attempt to match it’s value to either “SampleApp1” or “SampleApp2”
If there is a match, I use the Then condition to override the traffic routing and point to one of the other backend pools; as each of those pools points to only one Function App, this effectively routes to the function app as defined in the headers.
It’s probably a good time to point out it is evaluated from the top down, with multiple rules able to be applied. If multiple rules conflict with what they are doing, the one furthest down will take precedence. Additionally, if a rule matches you can stop processing by selecting the option to “Stop evaluating rule”. This is how you could consider it in code:
if (the value of the "x-preferred-backend" is "SampleApp1")
{
// Change the routing to point to the SampleApp1 routing pool
if (Stop evaluating rule is selected)
{
return;
}
}
if (the value of the "x-preferred-backend" is "SampleApp2")
{
// Change the routing to point to the SampleApp2 routing pool
if (Stop evaluating rule is selected)
{
return;
}
}
return;
If no rules match then the standard routing rule is followed.
After saving the engine, there is one final thing to do, and that is go back to the designer and associate the routing rule to the rules engine.
Believe it or not, you can check this in Postman. Call it a few times to make sure it is following the rules.
That’s it! That’s all I needed to do to be able to direct web traffic based on request headers. What I was looking at is header-based routing, but the rules engine can have rule conditions based on
- Whether your using a mobile or desktop
- Arguments in the post call body
- Argument sin the query string
- IP or Geolocation details of the originating request
- Content in the request body
- If the request is for a file, either the file name or the extension
- The request URL
- The request method (GET, POST, etc…)
- The request path
- The request protocol
And you don’t need to redirect traffic either, you can add, overwrite, or delete request or response headers to the call as well.
This is seriously awesome, and exactly what I was looking for when Front Door initially came out. I have previously written that I was burnt with unexpected costs regarding Front Door, so be careful when it comes to that.