Guest post by Thomas Denney Microsoft Student Partner at the University of Oxford.
Over the last few years cloud providers have shifted from offering Infrastructure-as-a-Service to Platform-as-a-Service, helping to reduce the knowledge required to maintain web apps and increase abstraction over maintenance and scaling. Function-as-a-Service, also known as serverless, is the next stage of abstraction, as developers instead write functions that respond to HTTP requests, execute after an event, or execute on a specified schedule. Resource management for the function is handled by the cloud provider, allowing for automatic scaling across multiple regions, and the developer isn't charged for when they aren't executing, which can reduce operating costs for a cloud service.
As each execution of the function could happen inside a different VM, on a different physical service, or even in a different continent. Therefore serverless encourages inherently stateless functions, which makes functional languages like F# a great tool for developing Azure Functions.
Getting started
To create an initial F# Azure Function you'll need to begin by creating a new Function App , which is a service that manages the resources for multiple related functions. When you create a Function App you'll have to option to either use the Consumption Plan or the App Service plan . This article will only use the Consumption Plan, which bills by execution time, but the App Service plan may be more appropriate if you have existing VMs or want more predictable billing. At the time of writing Microsoft doesn't bill for the first 1,000,000 executions of an Azure Function per month so it is unlikely you'll be charged anything whilst creating the REST APIs described in this article. The function app only takes a couple of minutes to deploy, at which point you're ready to start writing F# functions.
   Once your function app is deployed you can create a new function. The current UI only shows the option to create a C# or Node.js function, but if you click
   
    Create your own custom function
   
   you'll have the option to create a new F# function. Select the
   
    GenericWebHook-FSharp
   
   function and give it a name.
  
   The default function responds to a
   
    POST
   
   request with a simple greeting. To test this you can either run the function from within the Azure portal, or run the following
   
    curl
   
   command:
  
   curl -"Content-Type: application/json" -d "{\"first\": \"azure\", \"last\": \"function\"}" https://<appname>.azurewebsites.net/api/<functionname>?code=<code>
  
  To get a key (code) to use with your app, click on Keys on the right hand side in the Azure portal, or click Manage under your function name on the left hand side.
To make development and deployment of functions easier, we'll next set up local deployment from git, although other deployment approaches such as Visual Studio Team Services, GitHub, or OneDrive can be used:
- 
    Go to the
    
     Function app settings
    
    
 
- 
    Click
    
     Configure continuous integration
    
    
 
- 
    Under
    
     Deployments
    
    , click
    
     Setup
    
    
 
- 
    Click
    
     Configure Required Source
    
    under
    
     Choose Source
    
    
 
- 
    Select
    
     Local Git Repository
    
    
 
- Setup basic authentication
Once you've configured the deployment, you can run the following to make a local copy of the repository:
   git clone https://<git_username>@<app_name>.scm.azurewebsites.net:443/<app_name>.git
  
  It is possible to test functions locally using the Azure Functions CLI, although it is currently in beta and does not support non-Windows platforms . Alternatively, you could locally develop precompiled functions .
Creating a minimal JSON API
   Before creating something more interesting, it is worth adapting the default API to produce a minimal JSON API. Begin by creating a new directory
   
    hello
   
   in your git repository, and in that folder create a new file
   
    function.json
   
   . This file is used to specify the route for the API, the HTTP methods that can be used, and the authentication level required. Our new API will not require an authentication key (hence why
   
    anonymous
   
   is used for the
   
    authLevel
   
   ):
  
    {
    
    "bindings": [
    
    {
    
    "type": "httpTrigger",
    
    "direction": "in",
    
    "name": "req",
    
    "methods": ["get"],
    
    "route": "hello/{name:alpha}/{age:int}",
    
    "authLevel": "anonymous"
    
    },
    
    {
    
    "type": "http",
    
    "direction": "out",
    
    "name": "res"
    
    }
    
    ]
    
    }
   
  
   Routes are specified using
   
    route constraints
   
   , which allow you to specify the desired type of each of the URL parameters. Here we specify a string parameter
   
    name
   
   that only uses uppercase or lowercase letters, and an integer
   
    age
   
   parameter. These parameters are then mirrored exactly by parameters to the function.
  
   Next, create a new file
   
    run.jsx
   
   in the
   
    basic
   
   directory:
  
    #r "System.Net.Http"
    
    #r "System.Runtime.Serialization.dll"
    
    
    open System.Net
    
    open System.Net.Http
    
    open System.Runtime.Serialization
    
    
    // Using DataContract and DataMember annotations allow us to specify the output
    
    // field name; by default it will be Greeting@
    
    [<DataContract>]
    
    type Greeting = {
    
    [<field: DataMember(Name="greeting")>]
    
    Greeting: string
    
    }
    
    
    // This function is executed by the Azure Function environment. Microsoft
    
    // recommends that this function uses async tasks, although it is not strictly
    
    // necessary
    
    let Run(req: HttpRequestMessage, name: string, age: int, log: TraceWriter) =
    
    async {
    
    try
    
    return req.CreateResponse(HttpStatusCode.OK,
    
    { Greeting = sprintf "Hello %s, aged %d!" name age })
    
    with _ ->
    
    return req.CreateResponse(HttpStatusCode.BadRequest)
    
    } |> Async.StartAsTask
   
  
   You can perform requests to this API via the following
   
    curl
   
   command:
  
   curl https://<appname>.azurewebsites.net/api/basic/<name>/<age>
  
  Parsing query parameters
   Whilst embedding parameters for a
   
    GET
   
   API into the URI isn't uncommon, they more commonly appear as parameters at the end of the URL (i.e. in the form
   
    ?key=value&...
   
   ). Typically an API will have optional and required parameters, and the required parameters may need to be parsed (e.g. converting the string representation to an integer). We can take advantage of the functional idioms in F# to do this succinctly:
  
    exception MissingParam of string
    
    exception MalformedParam of string
    
    
    // This is a helper function that we use for converting the sequence of key
    
    // value pairs into a map (F#'s immutable equivalent of a dictionary)
    
    let paramsMap x = x |> Seq.map (fun (KeyValue (k,v)) -> (k,v)) |> Map.ofSeq
    
    
    // If the parameter has been specified in the request, then we attempt to parse
    
    // it using the function f, which should take a string and return a value of the
    
    // desired type. For example, when we just want to get the string later on we
    
    // specify the identity function id, but when we want to parse the string as an
    
    // integer we instead use the System.Int32.Parse function. If the function f
    
    // throws an exception we then throw the malformed parameter exception (defined
    
    // above) so that an appropriate error message is returned by the API.
    
    // Alternatively, if the parameter wasn't specified we throw a missing parameter
    
    // exception
    
    let reqParam f k m =
    
    match Map.tryFind k m with
    
    | Some x -> try f x
    
    with
    
    | _ -> raise (MalformedParam k)
    
    | None -> raise (MissingParam k)
    
    
    // For optional parameters we instead pass a default value, d, which is returned
    
    // in the case that the parameter is missing. 'd' and 'f x' should have the same
    
    // type
    
    let optParam f k d m =
    
    match Map.tryFind k m with
    
    | Some x -> try f x
    
    with
    
    | _ -> raise (MalformedParam x)
    
    | None -> d
    
    
    let Run(req: HttpRequestMessage, log: TraceWriter) =
    
    async {
    
    try
    
    let ps = req.GetQueryNameValuePairs() |> paramsMap
    
    // With the helper functions defined as above it is now
    
    // straightforward to retreive required and optional parameters
    
    let text = reqParam id "text" ps
    
    let count = optParam System.Int32.Parse "count" 1 ps
    
    // The final output of this API is a greeting, repeated a specified
    
    // number of times
    
    let g = sprintf "Hello %s. " text |> String.replicate count
    
    return req.CreateResponse(HttpStatusCode.OK, { Greeting = g })
    
    with
    
    // We can also provide meaningful responses in the case of errors
    
    | MissingParam(p) ->
    
    return req.CreateResponse(HttpStatusCode.BadRequest, sprintf "Missing param '%s'" p)
    
    | MalformedParam(p) ->
    
    return req.CreateResponse(HttpStatusCode.BadRequest, sprintf "Malformed param '%s'" p)
    
    | _                 -> return req.CreateResponse(HttpStatusCode.BadRequest)
    
    } |> Async.StartAsTask
   
  Scheduled functions
   Another simple use case for Azure Functions is to run a piece of code on a regular schedule. Begin by creating a new directory
   
    timed
   
   and create a new file
   
    function.json
   
   inside it:
  
    {
    
    "bindings": [
    
    {
    
    "schedule": "0 */5 * * * *",
    
    "name": "myTimer",
    
    "type": "timerTrigger",
    
    "direction": "in"
    
    }
    
    ]
    
    }
   
  
   Defining our function, inside
   
    run.fsx
   
   is straightforward:
  
    let Run(myTimer: TimerInfo, log: TraceWriter ) =
    
    DateTime.Now.ToLongTimeString() |> sprintf "Executed at %s" |> log.Info
   
  This gets the current date, formats a string with it, and then logs that string every time the function is executed. After deploying the function with git you can view the logs in Azure (you can also force the function to run by click Run ):
Conclusion
This article has shown how to develop Azure functions in F# that run on a schedule and respond to HTTP requests, thus providing the basis for a larger web app. As well as F#, it is possible to "bring your own runtime", although this isn't yet officially supported , or more common web backend languages, such as C# or Node.js .
Additional resources for developing Azure functions:
- 
    
     Azure Functions F# Developer Reference
    
    
 
- 
    
     Publishing a .Net class library as a Function app
    
    
 
- 
    
     Serverless framework
    
    for developing event-driven serverless apps
    
 
- Scheduled code execution with Azure Functions