all Technical posts

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

When using the Microsoft Azure stack, 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 within 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 immediately get 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, that gives you more configuration options.

 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.

  • 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. For every available pizza, add 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 Shared 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

  • Create a proxy GetProductViaBlobStorage. Provide the following details:
    Route template: api/product/{productId}
    Allowed HTTP methods: GET
    Backend URL: https://pizzadeliverystorage.blob.core.windows.net/pizza/pizza-{productId}.json?%BLOB_SAS_QUERYSTRING%

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

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 operations 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 also contains quite a 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

  • Create a proxy PostOrderViaLogicApps. Provide the following details:
    Route template: api/order
    Allowed HTTP methods: POST
    Backend URL: https://prod-07.westeurope.logic.azure.com/workflows/370c425e220142cda2e0d0ec8c983e91/triggers/manual/paths/invoke/order/create?%LOGICAPPS_SAS_QUERYSTRING%

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

  • Also create 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.

  • 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

  • Create a proxy GetOrderViaAzureFunctions. Provide the following details:
    Route template: api/order/{orderId}
    Allowed HTTP methods: GET
    Backend URL: https://pizzadeliveryservice.azurewebsites.net/api/orders/{orderId}?%FUNCTIONS_CODE_QUERYSTRING%

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. It 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 always want them to be returned 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!

Toon

Subscribe to our RSS feed