Showing posts with label Serverless. Show all posts
Showing posts with label Serverless. Show all posts

Monday, August 31, 2020

Accessing Config Data in Azure Functions with F#

I've been building an application using Azure Functions with F# as the API backend. The Azure Functions access data in Azure Storage to return to a single page web application. For development purposes, I've had the connection string hard-coded in the F# files that needed it. I'm at a point where I need to start deploying this app in a production manner, so I need to get the connection strings out of my code. The documentation for Azure Functions recommends using environment variables in production, and the local.settings.json file for development. Reading these values should have been trivial, but wasn't. This post documents how I was finally able to read data from environment variables.

Most of the documentation that I was able to find online pointed to using the Environment.GetEnvironmentVariable("myData") syntax. I was absolutely unable to get this call to work for me in my F# function. Fortunately I'm a member of the F# Slack community. I reached out for help on this issue, and Zaid Ajaj gave me a few things to try. This experimentation led to the solution below:

In the function above, I create a new ConfigurationBuilder instance and configure it for my app. To properly configure it, I needed to include another parameter for the function call, (context: ExecutionContext). This parameter gives me access to the runtime directory with the property context.FunctionAppDirectory. This allows me to then inject the local.settings.json file. (Note the boolean value true in the call to AddJsonFile. This true indicates that this file is optional, which is necessary in a production setting when this file will not exist.). Once I build the ConfigurationBuilder, I'm able to access local settings and environment variables using the array accessor syntax, config.["BoogyMan"].

I'm not sure if this is the "approved" Microsoft way or the best way to read environment values in an F# Azure Function, but it does work. If there is a better way to to this, I would love to see it.

Wednesday, June 3, 2020

F# and Azure Functions

Lately I've been creating tools for my wife to use with her classroom to help with distance learning. I've implemented these tools using Azure Functions. Azure Functions are the serverless computing option on the Azure platform. I picked these because I'm familiar with Azure and they are a quick, cheap option for standing up an API.

Another reason I picked Azure Functions is because they support creating functions in F#. I have been able to create a function project and function in F#, and at times run it locally, but I have struggled to get an F# function working in the cloud. I assumed that this issue was a combination of spotty support for F# in some areas, and my lack of understanding about how to get F# to play nicely as an Azure Function.

I have a new project I want to start as a series of Azure Functions, so I wanted to give F# another try. In my reading, I found this step-by-step guide by Luis Quintanilla for manually creating Azure Functions in F#. Luis does a great job walking the reader through creating a function in F#, without relying on the built-in templates provided by Microsoft. I found this guide fantastic because it gave me a better understanding of the composition of an Azure Function, AND it got me closer to successfully deploying an F# function.

The guide isn't perfect. It's missing some steps around adding necessary packages to the project that are referenced in the function itself (easy to do). This "gap" helped me discover some version discrepancies between by installed version of the .NET Core SDK and the Azure Function CLI tool. At first it appeared to be an issue with my project templates being out of date, but updating the templates didn't seem to fix anything. Ultimately, I updated my version of the .NET Core SDK to the latest version, and I upgraded my version of the Azure Function CLI.

At this point, my function that I created by following the guide worked locally and in the cloud! I went back and re-created my function using the command-line tools, and that worked as well. Using version 3.1.300 of the .NET Core SDK and version 3.0.2534 of the Azure CLI tools (which are targetting the Azure Function Runtime version 3.0.133353.0), the following steps will successfully create an Azure Function in F# that will work in the cloud:

mkdir HelloWorld
cd HelloWorld
dotnet new func --language F#
dotnet new http --language F# --name PrintHello
dotnet build
func start

The logging displayed in the console from the func start command will provide the URL for the local function. Pointing your browser to that URL will activate the locally running function.

I'm now ready to start creating larger applications in F#!

Wednesday, May 6, 2020

Quick Intro to Azure Functions

I've been working on a small web application for my wife to help her evaluate her preschool students. I created this application as a single page application (SPA) and backing APIs. For the SPA, I used VueJS. For the backing API, I used Azure Functions.

Azure Functions are Microsoft's serverless computing offering. They allow a developer to create functionality based on several triggers. Triggers can be HTTP, queues, Azure Storage, and so on. One of the most commonly used triggers is HTTP. A function based on an HTTP trigger fires for a web request. I think about this like a Model View Controller (MVC) application with the models and controllers and none of the boilerplate code that goes with a full API application.

An Azure Function application consists of a minimum set of files. Those files are:

host.json
local.settings.json
FunctionApp.csproj
Function.cs
Where "FunctionApp" and "Function" are the names you give your Azure Function.

The host.json file contains runtime information, including the version of Azure Functions being used and things like logging configurations. The local.settings.json file contains application-specific settings including connection strings. The CSPROJ file is a fairly typical C# project file that specifies any package dependencies and things like that. The CS file is the "function" itself. It looks like a typcial static C# class except for an annotation and a specific method signature.

The "function" that serves as a trigger for your function app is annotated with [FunctionName("MyFunction")]. This annotation specifies the publicly visible name that your function will have. The function signature is specific to the type of trigger for your function. Since I used an HTTP trigger, my function signature looked like:

public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
This signature tells the runtime that I am using an HTTP trigger that responds to HTTP GET and POST requests. I don't specify a specific route. The HttpRequest and a default logger are supplied using the dependency injection that is baked into the service.

When you generate your first function, a default "Hello World" app is created. This application illustrates how to work with the HttpRequest object passed into the function. It also shows how to create the IActionResult to pass output from the function.

For my specific Azure Function app, I put just enough code into the function itself to handle the request and return a response. I created service and repository classes for handling the business logic and data movement for the calls. This approach worked very well for me!

This approach to API development allowed me to get something created and deployed very quickly. I was able to utilize some basic tooling from Microsoft to build, test, and deploy my API very quickly.