Return to front page

Creating a birthday invitation handler

If you want to skip the setup for my situation, press me. I am not an expert, but learning and experimenting myself

Instead of sending my birthday invitations through text, I wanted to implement some Azure service in to the mix. After thinking about it for a while I decided to go with Azure Functions and Azure Static Web App.

The plan was to give people unique address links with unique identifiers where they could send a HTTP request that was handled and saved with Azure Functions to a storage account as a csv.

Components used

Azure Static Web App

The idea arose from the free Azure Static Web App. After starting it up I wanted to implement something around it, and chose this as my first project.

I created a set of simple html sites with a form and a submit button. Then, I pointed the form action to my Azure Function's URL. I also added a hidden form value "participant_id" that I used to determine who sent the response, that id was the same that was appended to the site URL. The users of course can just edit the call parameters using inspect if they want.

You can check out the example site here. Check out the source by right-clicking and selecting "Inspect" or pressing F-12.

Azure Function

I created a simple Azure function from a HTTP template that parsed the values from request body and saved them as a csv to the Azure Storage. Finding the TextWriter class was surprisingly hard and ultimately was found from a StackOverflow answer. But I knew what I was looking for and that I just needed the correct class to not have to define the Storage Account in the function code. As I developed the function in Azure Portal I also used the App Insight and Filesystem Logs in the development process.

Below are code blocks that form the Azure Function part and an example of the created CSV file.

Function code (run.csx) We get the wanted values from the HttpRequest body using IFormCollection. Then we check if the attending value is present as this tells us whether the checkbox was checked or not. In the end we save the answer to the Storage using the TextWriter binding "response"
#r "Newtonsoft.Json"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;

public static async Task Run(HttpRequest req, ILogger log, TextWriter response)
{
    log.LogInformation("C# HTTP trigger function processed a request.");
    IFormCollection form = await req.ReadFormAsync();

    string participantId = form["participant_id"];
    string attending = form["attending"];
    int participantAmount = int.Parse(form["participant_amount"]);
    string participants = form["participants"];
    string notes = form["notes"];

    string responseMessage = "";

    if (string.IsNullOrEmpty(attending)) {
        responseMessage = "Im sorry to hear that you won't be joining :(";
    } else {
        responseMessage = string.IsNullOrEmpty(participants)
            ? "Please fill the participants and try again"
                    : $"Hello, {participants}. I'm happy to hear that you will be joining";
    }

    response.WriteLine($"{participantId};{attending};{participantAmount};{participants};{notes}");

    return new OkObjectResult(responseMessage);
}
Binding json (function.json) We've created a binding to our storage account. Connection is a Function App setting that contains the connection string to our storage account. Name tells how to access the binding in the function itself and path tells where the output will be created.
{
  "bindings": [
    {
      "authLevel": "function",
      "name": "req",
      "type": "httpTrigger",
      "direction": "in",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "name": "$return",
      "type": "http",
      "direction": "out"
    },
    {
      "name": "response",
      "path": "responses/{sys.utcnow}.csv",
      "connection": "ConnectionStringSetting",
      "direction": "out",
      "type": "blob"
    }
  ]
}
Example CSV file content The files were found under the Storage Account - Containers - Responses with a file name like 2023-06-20T11:30:00Z.csv.
99905-12345;on;2;Guest1 and Guest2;Allergic to hangovers

Azure Storage

I used a standard Azure Storage Account and created a responses container to it.

Conclusion

I had a few thoughts about refining the process further;
implementing a participant_id replace in the function to auto parse the senders to the CSV files,
appending the file contents to a single file instead of creating one file per response.

I think this was a good way to familiarize myself with Azure Functions. Disregarding the binding class that I wanted to use everything was clearly documented and clear to use. No need to worry about the costs either using the free Static Web App and with around 200 calls to the Function itself the cost was still at 0,00.

In the end, I decided to send the invitations with text messages, but it was a fun project to implement.

Return to front page