azureasp.net-web-apiasp.net-web-api2azure-functionsazure-function-app-proxy

Adapting hypermedia links based on environment


I have an on-premise ASP.NET Web API that's querying on-premise data. The plan is for the client web application to call an Azure Function which will deal with authentication (Azure AD B2C) and validating the request before actually forwarding the request to the on-premise API itself (over a VPN).

The API is generating Hypermedia links that point to the API itself. This works nicely when querying the API directly as each of the links helps in the discovery of the application.

This API is currently in use locally within the organisation, but we now need to expose it so it can be consumed over the web. We don't want to expose the API directly, we'd rather route it through a Function App that can authenticate, validate and perform any other logic we may need.

The question I have is, how would you translate these URLs to an endpoint in the Azure Function? i.e., I would really like the consuming web application to be able to use these Hypermedia links directly, and have the Azure Function route them to the correct API endpoint.

In an ideal world, we'd have the links exposed on the client, which would map to the resource. As the API isn't exposed, how do we route it via the Function App?


Solution

  • It sounds like what you want is for Azure Functions to operate as a reverse proxy.

    One trick to achieve this is to have one HttpTrigger that catches all traffic that hits your function application. You can do this by setting the properties route: "{*uri}" and methods: ["get", "post", "put", "patch", "delete"] in the function.json. You can add additional HTTP methods to the methods list as necessary. These should catch all requests in the form "https://{app-name}.azurefunctions.net/api/*".

    The code below is a rough outline of how you could achieve the redirect from your function app to the unexposed API. In it's current representation, the relative URI path after /api/ will be redirected to your unexposed api with the exact same body request.

    using System.Net;
    
    public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
    {
        //Validation logic here
    
        string actualUrl = "{hosturl}/";
        string proxyUrl = "https://{app-name}.azurewebsites.net/api/";
    
        req.RequestUri = new Uri(req.RequestUri.ToString().Replace(proxyUrl, actualUrl));
        req.Headers.Host = req.RequestUri.Host;
        using(var client = new HttpClient())
        {
            return await client.SendAsync(req);
        }
    }
    

    You can now generate all of your Hypermedia links pointing to your function hostname, and they will be properly redirected.

    NOTE: If you expect many instances of the function to spin up (i.e. a high concurrent usage of your function), then it is possible that you will run into SocketException errors as documented here.