Azure Function Proxies – Part 1: Represent heterogenous service operations into a single API

This post is part of an Azure Function Proxies blog series:

  • Part 1: Represent heterogenous service operations into a single API
  • Part 2: Easily enable hybrid integration
  • Part 3: Secure your API
  • Part 4: A very light-weight API management

When using the Microsoft Azure offering, an important aspect is to use the right service for the job.  In this way, you might end up with an API that is composed of several Azure services such as Blob Storage, Logic Apps and Azure Functions.  In order to publish such an API in a unified way, you can leverage Azure Functions Proxies.

Scenario

In this fictitious scenario, I’m building a Pizza Delivery API.  It’s composed of the following operations:

  • GET Products is still in development, so I want to return a mocked response.
  • GET Product returns the product information from Blob Storage.
  • POST Order invokes a Logic Apps that creates the order in an async fashion.
  • GET Order call an Azure Function that retrieves the specific order information
  • PUT Order is responsible to asynchronously update an order via Logic Apps
  • DELETE Order removes the order from within a Logic App

Proxies - 01

In this blog, I’ll show you how to build this API, without writing a single line of code.

Walkthrough

Introduction

This section just demonstrates the basic principles to start creating your first Azure Function Proxy.

  • Azure Function Proxies is still in preview.  Therefore, you need to explicitly enable it on the Settings tab.

Proxies - 02

  • Now, you can create a new proxy, by using the “+” sign.  You need to specify a name, a route template, the allowed HTTP methods and a backend URI.  Click Create to save your changes.

Proxies - 03

  • When the proxy is created, you get immediately the proxy URL on which you can invoke the Azure Function Proxy.  Via the Advanced editor link, you can define more options in a JSON format.

Proxies - 04

  • The advanced editor is a JSON editor of the proxies.json file.

Proxies - 05

After this introduction, we can start the implementation of the Pizza Delivery API.

Mocking

This operation won’t have a backend service, because it’s still in development.  We will mock a response, so the API can already be used for development purposes.

  • Create a proxy GetProductsViaMocking.  Provide the following details:
    • Route template: api/products
    • Allowed HTTP methods: GET
    • Backend URL: none, we will use mocking

Proxies - 06

  • In the Advanced editor, specify the following responseOverrides.  This sets the Content-Type to application/json and the response body to a fixed list of pizzas.
"responseOverrides": {
   "response.headers.Content-Type": "application/json",
   "response.body": "[{\"Id\": 1, \"Name\": \"Pizza Margherita\", \"Description\":  \"Excellent!\"},{\"Id\": 2, \"Name\": \"Pizza Quattro Formaggio\", \"Description\":  \"Delicious!\"},{\"Id\": 3, \"Name\": \"Pizza Funghi\", \"Description\":  \"Fantastic!\"}]"
}

Untitled picture

  • If you test this GET operation, you’ll receive the mocked list of three pizzas!

Proxies - 07

Blob Storage

The GET Product operation will return a JSON file from Blob Storage in a dynamic fashion.  Blob Storage is an easy and cheap way to return static or less frequently changing content.

  • Create a blob container, named “pizza”.  Set its access level to private, so it’s not publicly accessible by default.  Add for every available pizza, a JSON file that holds the product information.

Proxies - 08

  • Create an Access Policy on container level.  The policy provides read access, without any expiration.  You can easily do this via the Azure Storage Explorer.

Proxies - 09

  • Create a Share Access Signature from this policy, via the Azure Storage Explorer.  This gives you a URL (containing the SAS token), to access the blobs from the “pizza” container.

Proxies - 10

  • To keep the SAS token better manageable, I prefer to add the SAS query string to the Application Settings of our Function App.  Create an Application Setting BLOB_SAS_QUERYSTRING.

Proxies - 11

Remark that the route template parameter ‘productId’ is reused in the Backend URL to get to correct JSON file.  Remark that the application settings can be retrieved via this %BLOB_SAS_QUERYSTRING% syntax

Proxies - 12

  • In the Advanced editor, specify the following responseOverrides.  This sets the Content-Type to application/json
"responseOverrides": {
   "response.headers.Content-Type": "application/json"
}

Proxies - 13

  • If you test this GET operation, you get the product description of the corresponding product id.

Proxies - 14

Logic Apps

The asynchronous order operation will be tackled by a Logic App that puts the commands on a ServiceBus queue.  Further downstream processing is not covered in this post.

  • Create a Logic App as shown below.  Remark that the request trigger contains an {operation} parameter in the relative path.  The request command is sent to an orderqueue, with the {operation} as a message property.

Proxies - 15

  • Get the request URL from the Logic App.  This contains also a quite long query string, that includes the API version and the SAS token.  Similar to the previous step, insert the query string into an Application Setting named LOGICAPPS_SAS_QUERYSTRING.

Proxies - 16

Remark that the create operation is passed via the Backend URL

Proxies - 17

  • If you test this POST operation, you’ll notice that the message is accepted.

Proxies - 18

  • In the Logic Apps Run History, you should see that a new Logic App instance got fired.

Proxies - 19

  • The message is now placed on the Service Bus queue.  The operation has been set to create.

Proxies - 20

  • Create also a proxy for the PUT and DELETE operation, in a similar way.

Proxies - 21

Azure Functions

  • I’ve created an Azure Function that just returns a dummy order.  The returned order ID is taken from the request.
#r "Newtonsoft.Json"
using System;
using System.Net;
using Newtonsoft.Json;
using System.Collections.Generic;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage request, int orderId, TraceWriter log)
{
    log.Info($"Webhook was triggered!");

    var order = new Order();
    order.Id = orderId.ToString();
    order.Name = "Toon Vanhoutte";
    order.OrderLines.Add(new OrderLine(1, 3));
    order.OrderLines.Add(new OrderLine(3, 2));

    return request.CreateResponse(HttpStatusCode.OK, order);
}

public class Order
{
    public Order()
    {
        OrderLines = new List<OrderLine>();
    }

    public string Id { get; set; }
    public string Name { get; set; }
    public List<OrderLine> OrderLines { get; set; }
}

public class OrderLine
{
    public OrderLine(int productId, int quantity)
    {
        ProductId = productId;
        Quantity = quantity;
    }

    public int ProductId { get; set; }
    public int Quantity { get; set; }
}
  • Deploy this Azure Function in a Function App and retrieve the URL.  The URL contains a query string with the required access code.  Add this query string to the Application Settings, named FUNCTIONS_CODE_QUERYSTRING.

Proxies - 22

Remark that the route template parameter ‘orderId’ is reused in the Backend URL to pass it on to the Azure Function.

Proxies - 23

  • If you test this GET operation, you’ll notice that a dummy order is returned, with the requested Id.

Proxies - 24

Feedback to the product team

After playing around with Azure Function Proxies, I have the following suggestions for the product team.  They are listed in a prioritized order (most wanted feature requests first):

  • The mocking experience is not ideal when working with JSON objects, as you need to constantly escape quote characters.  Would be great if this could be made more user-friendly.  As an alternative, you can reach out to blob storage, but this additional step decreases developer productivity.
  • It would be nice if there is a way to remove all or some HTTP headers from the response.  Each Azure service comes with its own set of HTTP response headers and I don’t want them to be returned always to the client application.  This would be great from both a security and consistency perspective.
  • Accessing parts of the request or response body would open up a lot of new opportunities.  As an example, I’ve tried to put the message immediately on an Azure Storage Queue, without any code in between.  However, this was not feasible, because I needed to wrap the original message content inside this XML template:
<QueueMessage> 
  <MessageText>OriginalMessageContent</MessageText> 
</QueueMessage>
  • Currently there is no way to perform different transformations, based on – for example – the backend response status code.  This could become handy in certain scenarios.

Conclusion

Azure Function Proxies can be easily used to create an API that consists of multiple HTTP-based (micro)services.  Practically every service can be accessed from within this light-weight application proxy, as long as the authentication is performed through the URL (e.g. SAS token, API key).  This avoids that the client application needs to maintain a different URL per operation it wants to invoke.  The service is very easy to use and requires no coding at all.  A great addition to our integration toolbelt!

Advertisements

8 thoughts on “Azure Function Proxies – Part 1: Represent heterogenous service operations into a single API

  1. Out of interest, presumably your Feedback points could be met by using API Management instead?

    I realise this post was to show what Azure Functions can do – but it might be worth knowing that the next step up in functionality is API Management.

    Like

    • Thanks for your comment! Completely agree that this is very light-weight api management and it comes nowhere near Azure API Management. I’ll discuss this in Part 4 of this series 😉

      My feedback to the product team is limited to basic operations on HTTP header and body level. I think they still might fit into the goal of Azure Function Proxies, but it’s up to the product team to decide on that 😉

      Thanks again!

      Liked by 1 person

  2. Pingback: Microsoft Integration Weekly Update: Sep 25, 2017 | Hooking Stuffs Together

  3. Pingback: Azure Function Proxies – Part 2: Easily enable hybrid integration | toon vanhoutte

  4. Hi @Toonvanhoutte

    Awesome post about Proxies and we’re enjoying going through your feedback!
    On your first point, you can totally paste JSON into a mock API without escaping all the quotes using the WebUI or the advanced editor. We’re looking to add some more JSON support to the webUI to make that whole experience cleaner.
    You can see an example of raw JSON in the responseOverrides body here: https://github.com/Azure-Samples/functions-proxies/blob/master/ProxiesSamples/proxies.json

    The other feedback is awesome! I’ve added github requests for each: https://github.com/Azure/azure-webjobs-sdk-script/issues/1967 https://github.com/Azure/azure-webjobs-sdk-script/issues/1968 https://github.com/Azure/azure-webjobs-sdk-script/issues/1969
    https://github.com/Azure/azure-functions-ux/issues/1844

    Like

  5. Pingback: Azure Function Proxies – Part 3: Secure your API! | toon vanhoutte

  6. Pingback: Azure Function Proxies – Part 4: A very lightweight API Management | toon vanhoutte

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s