Azure Functions fully supports F#, which raises the question of why we haven’t one for functional development. The reason is that there hasn’t been enough development done in the functional paradigm.
Giraffe meets Arcus
For developing Web APIs and Azure Functions HTTP triggers in F#, there’s a commonly used library called ‘Giraffe’ that helps overcome the tedious OOP-restrictions of the ASP.NET Core framework. The purpose of this post is not to explain Giraffe, as you can read their thorough documentation for more information on this framework.
All Giraffe needs is a reference in the
Startup.fs. Besides that, all of the Arcus registrations look almost the same in the official template:
Note that with Giraffe, we can only specify the JSON settings once, and then the input/output gets adapted directly.
The actual Azure Function HTTP trigger can be found in the
Run.fs file. I’ve already added some starter functions so you can get the idea of a simple Giraffe Azure Functions setup. In the next steps, we’ll look at how we can introduce the boilerplate code that you find in the official Arcus Azure Functions HTTP trigger project template.
The Azure Functions HTTP trigger template contains some request restrictions to make sure that the HTTP request is valid. Normally, this is done in some middleware, but since we’re in Azure Functions (and not yet in out-of-process functions), we will assume that there’s no middleware available.
The Arcus project template uses a re-usable base class to provide you with some functionality to restrict the request. Fortunately, with Giraffe we can simply use functions for this.
I’ve created some functions in the Arcus style on a personal GitHub repo which can directly be referenced in F# paket projects. These functions will help with making sure that the incoming request has the correct metadata information before we do any binding or serialization. Here are some examples added to the Azure Function:
The Arcus correlation is now fully functional and can be added to our Giraffe pipeline:
To deserialize the request body, we provided some binding methods in the base class. With a concrete JSON exception type, we’ve handled any problems during deserialization. In Giraffe, the same sort of thing can be accomplished. We should make sure that we also verify any validation attributes on the type we’re trying to bind. All this functionality is also available in F#.
First things first, let’s start with our JSON model. Luckily, we can simply use F# records for this:
To deserialize, we can use Giraffe’s
.BindJsonAsync. Since we also need some additional error handling, let’s wrap these in a separate higher-order function to take in the successful flow:
To validate the model, we can use the Giraffe’s
IModelValidation interface. With a little tweak, we can let it validate our ASP.NET Core validation attributes:
validateModel Giraffe pipeline function (
f:('T -> HttpHandler) -> model:'T -> HttpHandler) will take care of this. In combination with our previously added JSON deserialization function, our Giraffe pipeline now looks like this:
Note that the
validateModel function takes in a result function where the successful validation result should be sent to (like our
tryBindJson function does). I’ve chosen here to take the same approach as with the Arcus template, and have sent back the order with Giraffe’s
As a bonus, try to introduce a domain model with some domain model requirements, and to parse that model. With my personal FPrmitive package, this can be done rather easily in the same functional manner. For more information on this package and examples on how this library can be used, see my other blog posts.
In this post, we’ve looked at some alternative ways to provide users with a starter project that already does much of the highly-needed boilerplate code. We’ve seen that with Giraffe and the built-in F# support for Azure Functions, we can accomplish a lot.
Hopefully, you will consider F# as an option in your next project, because it’s definitely worth a look. Combining C# and F# is even better.
Thanks for reading!
Subscribe to our RSS feed