United Kingdom: +44 (0)208 088 8978

Creating Azure Functions with Farmer

Farmer can be used to quickly and easily create Azure Functions instances. Here, we compare some of the design decisions of the Farmer and Bicep projects by looking at how to create a Functions instance with both technologies.

Microsoft have recently opened access to their upcoming Bicep project - a brand new language and toolchain which is being developed that compiles down to ARM templates, in a similar fashion to Farmer.

One of the key differences between Farmer and Bicep (and, to an extent, other tools like Pulumi or Terraform), is the layer of abstraction between the language you work with, and the ARM templates that are emitted:

  • Farmer starts from the perspective of the consumer of the resources.
  • Bicep remains at a 1:1 level of ARM template.

A great example of this is visible here with this excellent sample that Jack Tracey (a Microsoft CSA) has put together for creating a Functions app :

See here for the full Bicep and generated ARM template file.

Bicep brings some improvements compared to writing raw ARM:

  • Simpler variable declarations
  • Simpler syntax
  • Ability to implicitly infer dependencies based on usage

This last one is a useful feature as if you forget to set dependencies, your deployment may work intermittently and then suddenly fail.

Abstraction differences

However, the core ARM abstractions remain:

  • Creation of a server farm, web app, storage account and app insights instances
  • Configuration of all of those (including understanding of connection string formats, SKUs etc.)
  • Understanding the relationship between each of these

None of this should matter to a developer who simply wishes to use Azure Functions!

In Farmer, we take a very different approach by working with a tastefully designed abstraction that sits above all of those resources:

let myFunctions = functions {
    name "myFunctions"
}

let template = arm {
    location Location.NorthEurope
    add_resource myFunctions
}

The three lines of code of the functions block encapsulates everything required to make a Functions app:

  • All four resources (Server Farm, App Service instance, Storage Account and App Insights)
  • Each resource connected to one another
  • Each resource fully configured
  • Location implicitly assigned from the template abstraction

All you need provide is the main logical name of your functions instance; all the other instances are created for you. You can see the full before / after code here.

Farmer can also go one step further and make use of features that are offered by the Azure CLI. For example, here we can also deploy our functions code to the infrastructure as part of the Farmer deployment process:

let myFunctions = functions {
    name "myFunctions"
    zip_deploy "myFunctionsFolder"
}

In this case, you simply need to provide the folder of your published / compiled Functions application; Farmer will automatically zip it up and deploy into Azure for you.

Summary

Farmer and Bicep both are languages that compile down into ARM template JSON. However, one of the differences between them is that they a different approach to abstraction: Bicep lives at the ARM abstraction layer, whereas Farmer has higher-level abstractions designed to logically group resources for you, with the ability to drop down to the lower ARM resource level if required.