Azure Function as an HTTP endpoint

Article three describing my first foray into serverless computing. Introduction here, storage queue triggered function here. TL;DR: I’m using this is as a way to familiarize myself with Azure Functions, and to save some precious family time better spent not trying to remember what we need come Sunday.

In my projects, we always end up integrating against some kind of third party – be it booking systems, news aggregators, external providers of content or something as simple as an image resizer. Common for the integrations, is the need to transform the data received into a format with which we want to work. Sometimes we need to enrich the data  by combining it with other sources, and other times the data exposed by the external API is more than we need.

For this project, I had to get product data from‘s API by barcode in order to add the product to my cart using their internal ID. Their API provides a product endpoint, but it exposes much more data than I needed. I decided to abstract it away behind a GET endpoint of my own.

This is a philosophy I try to follow in all projects I’m responsible for. It means the business code can trust that the contracts we’ve agreed upon won’t break suddenly because of any external factors, and third parties are kept at the edges of the system. Another advantage in this case is that I might want to cache the product data returned at some point, and with the endpoint (function) in place, I have an easy way to implement said caching without having to modify any business code.

So, an HTTP endpoint was needed, and since I’m working in a serverless architecture, that meant I had to create an HTTP triggered function:

The HTTP triggered function is found in the “API & WebHooks” scenario,

Note that you can specify the access/authorization level for the function:


“Function” means the caller needs to provide a key which is specific to the function in the query string. “Admin” means an app wide key is needed, while “anonymous” will allow anyone who accesses the URL to trigger the function.

Now, the HTTP trigger is not always used as a RESTful endpoint – it can just as well trigger a processing job, write to a storage table or whatever else you need it to do, but in this case I wanted to return a product object on the format determined by the Accept-Encoding of the request.

In order to make the function return an http request, the function needs to have an HTTP output parameter, which is set up by default when you create the function. I left everything as it was, and focused on writing the small function:

#r "Newtonsoft.Json"
using System;
using System.Configuration;
using Newtonsoft.Json;
using System.Net;
// These are the (interesting parts) of the models returned from the kolonial API.
// The actual JSON returned contains more properties, but I see no reason to bother the deserializer
// with more than what we actually need.
public class KolonialSearchResponse {
public KolonialProduct[] Products {get;set;}
public class KolonialProduct {
public string Id {get;set;}
public string Barcode { get; set; }
public string Brand {get; set;}
public string Name {get; set;}
static HttpClient HttpClient = null;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
if(HttpClient == null)
HttpClient = CreateHttpClient(log);
string barcode = GetBarcodeFromRequest(req);
// Request product from kolonial
var httpResult = await HttpClient.GetAsync("" + barcode);
if (!httpResult.IsSuccessStatusCode)
// not much we can do here, so just log the error and return an error status code.
log.Error($"Error occured when getting data from kolonial.");
return req.CreateErrorResponse(HttpStatusCode.InternalServerError, "Product not found");
var json = await httpResult.Content.ReadAsStringAsync();
if (json != null)
log.Info($"Processing JSON: {json}");
var results = JsonConvert.DeserializeObject<KolonialSearchResponse>(json);
// If the search call returns anything but a single product
// we have no idea how to handle it.
if(results.Products != null && results.Products.Length == 1)
var product = results.Products.First();
product.Barcode = barcode;
return req.CreateResponse(HttpStatusCode.OK, product);
return req.CreateErrorResponse(HttpStatusCode.BadRequest, "Product not found");
public static HttpClient CreateHttpClient(TraceWriter log)
log.Info("Instantiating HTTP client.");
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("X-Client-Token", ConfigurationManager.AppSettings["KolonialToken"]);
httpClient.DefaultRequestHeaders.Add("User-Agent", ConfigurationManager.AppSettings["KolonialUserAgent"]);
return httpClient;
public static string GetBarcodeFromRequest(HttpRequestMessage req){
return req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "barcode", true) == 0)

Hopefully, the code should be pretty self-explanatory. There are a couple of things which are good to know, though: Newtonsoft.Json is available in azure functions, but it must be imported:

#r "Newtonsoft.Json"


And while I very much doubt that I would ever exhaust anything with the small scale of my project, the Microsoft patterns and practices team do recommend that HttpClient is instantiated as few times as possible, and instead kept in memory and re-used. That’s why the static HttpClient is created the first time the function is triggered and kept around:

if(HttpClient == null)
    HttpClient = CreateHttpClient(log);

What’s interesting is that despite the function in principle being serverless, the static variable will hang around (albeit for an unpredictable amount of time), effectively allowing us to follow best practice. You can read more about sharing state in Azure Functions on Mark Heath’s excellent blog.

When it comes to the formatting of the return value, the framework will take of that for you as long as you stick to the request.CreateResponse(…) functions. As an example, this is how the function responds to an Accept: application/json request:


While requesting XML, predictably, will return this:


(Both screenshots courtesy of the wonderful Postman Chrome plugin)

And that’s that – a small integration with an external service, contained in a single azure function.


Leave a Reply

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

You are commenting using your 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 )

Connecting to %s