Configuring HTTP Route Parameters in Azure Functions 2.x using Python

joegatt

Joe Gatt

Posted on January 4, 2020

Configuring HTTP Route Parameters in Azure Functions 2.x using Python

Overview of How HTTP Routing Works in Azure Functions

For a high-level overview of three popular HTTP routing patterns, refer to this blog post by Lori MacVittie from F5 networks. Moving forward, when I refer to HTTP routing in the context of Azure Functions for the balance of this blog post, I am referring to path-based routing.

HTTP routing in Azure Functions is responsible for mapping request URIs to endpoints and routing HTTP requests to those endpoints. Additionally, Azure Functions can extract values from the URI contained in the request and use those values for request processing. The latter is a useful way to pass multiple parameters to an HTTP trigger.

Route Prefix

As the name implies, you can customize or remove the default “api” route prefix for HTTP triggers in Azure Functions. See this documentation from Microsoft for reference. To change it, you modify the host.json file and add the following configuration setting:

{
  "extensions": {
    "http": {
      "routePrefix": "foo"
    }
  }
}

In the above example, we are setting the route prefix to “foo”. Please note: this setting is “global” in that if you are hosting more than one function in a function app, this setting will apply to all functions. Given the global nature of the setting, I have not found much value in modifying the default.

Route Parameters

As outlined above, an HTTP route can serve two purposes in Azure Functions: mapping request URIs to endpoints or request processing. Routes are defined in the function.json file and configured when the function app starts. According to the documentation, route parameter names must be non-empty and cannot contain these characters: {, }, /.

Mapping request URI’s to endpoints

This pattern is by far the easiest to implement. Let’s walk through an example where you want to host two versions of an HTTP trigger function in the same function app. In this example, we have an HTTP trigger function named “FirstName”. To add a version to the route, simply modify the function.json file and add the following configuration setting:

"route": "v1/FirstName",

Now you can create a similar HTTP trigger function named “FirstName2”, modify the function.json file and add the following configuration setting:

"route": "v2/FirstName",

You can use this feature to ensure that you do not break compatibility with functions that you publish or to route traffic to a given endpoint.

Request Processing with HTTP Route Parameters

Let’s walk through an example of using a route parameter to customize request processing. Consider the default HTTP trigger template, which takes data passed to the “name” parameter as input and outputs the data passed to the function. Imagine that you want to extend this function to take both a first name and last name, you would add the following to your function.json file:

"route": "FirstNameLastName/{firstname}/{lastname}"

And you would modify your function code to reflect the following:

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info("Python HTTP trigger function processed a request.")

    firstname = req.route_params.get("firstname")
    lastname = req.route_params.get("lastname")

    return func.HttpResponse(f"Hello {firstname} {lastname}!")

Notice that you use the “route_params” property instead of the “params” property. The full documentation for the HTTPRequest class for Python is here.

When you run your function locally, you will notice that the URL has been modified from the default:

FirstNameLastName: [GET] http://localhost:7071/api/FirstNameLastName/{firstname}/{lastname}

Route Constraints

Adding a constraint to your route parameter allows you to restrict how the routes in function.json are matched. The general syntax is “{parameter:constraint}”. For example, if we want to restrict our FirstNameLastName function to only accept alpha characters for the two routes we previously defined, we would configure it in function.json like the below:

"route": "FirstNameLastName/{firstname:alpha}/{lastname:alpha}",

Given the pay per transaction nature of Azure Functions, this is an excellent way to ensure that only valid transactions are processed by your function app. For a full list of route constraints, refer to this article here.

Please note: processing of route constraints is not performed by the function app but instead by the Azure Function Host. The Azure Function Host will return a 404 if you supply it a bad URI. I will cover this topic in a future blog post about debugging route parameters.

Mandatory vs. Optional Route Parameters

You can mark HTTP route parameters as optional, which gives you some flexibility in your code. The '?' character marks a parameter as optional and can occur only at the end of the parameter. For example, if we want to mark our last name route parameter as optional in our previous example, we would configure it in our function.json like the below:

"route": "FirstNameLastName/{firstname:alpha}/{lastname:alpha?}",

Please note that if you do not pass lastname to the above URI, the value of the lastname variable in your function code would be None. For example:

curl http://localhost:7071/api/FirstNameLastName/foo/bar
  Hello, foo bar!
curl http://localhost:7071/api/FirstNameLastName/foo
  Hello, foo None!

Please ensure to add proper error handling in your function app if you mark your HTTP route parameters as optional.

That’s it for now, in my next blog post I will cover how to debug HTTP routing parameters in detail. If you have any feedback, please send me a note at gattjoseph at < hotmail >.

💖 💪 🙅 🚩
joegatt
Joe Gatt

Posted on January 4, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related