tomling.dev ⚡
Published on

Azure Functions 2.0 HTTP routing options.

What is routing

Routing refers to how an application responds to a client request to a particular endpoint address and specific HTTP request method (GET, POST etc.). In the context of Azure Functions, the route defines which function will respond to an HTTP request.

Azure Functions Default Routing

To demonstrate the various routing options, I will be using the default Azure Functions 2.0 (.NET Core) HTTP trigger template, which looks like this (at the time of writing):

[FunctionName("NameFunction")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
    ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    string name = req.Query["name"];

    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    dynamic data = JsonConvert.DeserializeObject(requestBody);
    name = name ?? data?.name;

    return name != null
        ? (ActionResult)new OkObjectResult($"Hello, {name}")
        : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}

By running this locally, you can see that the default URL to call this function is http://localhost:7071/api/NameFunction This URL has a route prefix of API, then the name of your function, in this instance, 'NameFunction':

Default Routing Running the app exposes the default URL

Navigating to this URL in the browser supplied with a parameter with your name yields the following result:

Default Route Browser Result

Changing the route prefix with host.json

To change the app's default routing of /api/ the host.json file will need to be modified. This file contains global configuration options that affect all functions for a given function app.

To modify the route prefix, amend the host.json file to look like the following:

{
  "version": "2.0",
  "extensions": {
    "http": {
      "routePrefix": "Name"

    }
  }
}

This will turn http://localhost:7071/api/NameFunction into http://localhost:7071/Name/NameFunction.

To remove the route prefix, completely modify the routePrefix section of the host.json to match the following:

{
  "version": "2.0",
  "extensions": {
    "http": {
      "routePrefix": ""

    }
  }
}

This will turn http://localhost:7071/api/NameFunction into http://localhost:7071/NameFunction.

I can still call the API as I usually would by dropping it from the URL by removing the route prefix:

Remove Route Prefix Browser Result

Define the route in the function header

You can also define routing by modifying the HttpTrigger attribution in the function's header, setting it to null by default. Changing this value to 'GetName' will turn the URL into http://localhost:7071/api/GetName.

[FunctionName("NameFunction")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "GetName")] HttpRequest req,
    ILogger log)
{ ...

You can also change the route to a blank string. The URL will become http://localhost:7071/api/

Adding parameters to function routes

To add parameters to the route of your function, you will need to add the parameter name in curly braces in the route property of the HttpTrigger attribute and add it to the method parameters.

To demonstrate this refactor the default HTTP trigger code to match the following:

[FunctionName("NameFunction")]
public static IActionResult Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "GetName/{name}")] HttpRequest req,
    string name,
    ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    return new OkObjectResult($"Hello, {name}");
}

The URL will change to the following:http://localhost:7071/api/GetName/{name}

Instead of supplying the name via a URL parameter, I can provide it using a route parameter.

Route Parameter

If we do not specify a route parameter, we can not find any matching routes; the service will return a 404:

Route Parameter 404

Making route parameters optional

Supplying function parameters using routing, as demonstrated in my previous example, is an excellent way of making the URL of our function more human-readable and easier to consume. However, we have refactored our code to remove the friendly message to alert the user they have forgotten to supply the name parameter.

To add this message back into our function, we need to make our route parameter optional. We can achieve this by adding a ? to the parameter name in the route definition and the type in the function header parameters (this will make the value type nullable).

Refactor the code to the following.

[FunctionName("NameFunction")]
public static IActionResult Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "GetName/{name?}")]
    HttpRequest req,
    string name,
    ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    return name != null
        ? (ActionResult)new OkObjectResult($"Hello, {name}")
        : new BadRequestObjectResult("Please pass a name as a route parameter");
}

By specifying our name as a URL parameter, we can see our greeting message as expected.

Route Parameter

And by dropping the name, the parameter defaults to null and our reminder message is returned.

Route Parameter Not Found

Wrap Up

Hopefully, this serves as a fairly comprehensive guide on configuring routing on Azure Functions. Please let me know using my Twitter handle @tomlingdev if you have any questions.

Hello 👋 My name is Tom Ling.

I am a Security Engineer at ClearBank.