Month: February 2020

SAFE Adventures in F#

With my recent role change I’m getting most of my coding kicks for fun these days – which means I’m working almost entirely on OSS and get to play around with whatever takes my fancy! Exploring Fable and the broader SAFE stack has been on my list of things to do for some time and so this last weekend I dove in and got started building something simple.

If you’ve not come across the SAFE stack before its an entirely open source community driven end to end web development framework for F# that takes a functional first approach that brings together a number of projects:

  • Saturn – a web development framework that is ultimately running on top of ASP .Net Core
  • Azure – Microsoft’s cloud hosting platform. Doesn’t really “come” with SAFE (I think someone was reaching to make a cool name!) but it is a natural companion.
  • Fable – A F# to JavaScript transpiler.
  • Elmish – a set of abstractions for writing user interfaces in F#. Fable and Elmish come pre-configured with React bindings. Yes – you can write React apps in F# and using very familiar patterns.

Its worth noting that the excellent Fabulous framework, for mobile apps based on Xamarin Forms, also makes use of Elmish and I think makes a natural companion to the SAFE stack.

While I don’t intend to write an end to end tutorial I thought it would be useful to highlight some of the challenges I faced getting started and solutions I found. This will be a bit of a grab bag but lets dive into it…

Getting Started

Before you begin there are a few tools its useful to have ready. Firstly Visual Studio Code and Ionide are very useful for working on F#. Ionide is an open source community extension for VS Code and while I prefer to work on server side / backend code in Rider it contains some useful tools for working with Fable. We’ll come to my embryonic workflow later!

For now – ensure you’ve got Visual Studio Code and the Ionide extension for it. You’ll also want to have .NET Core 3 installed.

With all that done you can get started with your first SAFE project. There’s little point me repeating the documentation – to get started with a new project just follow the simple instructions on the SAFE website.

Working With The Solution

My first stab at working with the solution was to open it in Rider – my preferred IDE for all things .NET. It does all open but you need to do some work to get it to compile and run the client and I haven’t yet managed to get it debugging the client.

Next stop was VS Code which does work quite nicely – the out the box project includes all the configuration for VS Code to compile and run both server and client with an end to end debugging experience. Great! Except….

I found it a bit confusing and noisy having everything in one project. The console output is excessive and not well delineated and generally its just too much for my brain to deal with. It could be something I get used to in time but I’m fairly used to having my client code in VS Code and my backend code in Rider.

It was super simple to create two new solutions from the shipped sln file – one for client and one for server – and then I could work in a pattern I found more comfortable.

Custom HTML Attributes

Sooner or later you’ll come across a piece of HTML / JavaScript that makes use of custom attributes on HTML tags, for example “x-data”. Given that Fable-React makes use of a type safe discriminated union for HTML attributes how do we do this? Handily their is a member of the union called Custom so you can write something like:

div [Custom("x-data", "somevalue") ; ClassName="my-class"] []

Converting HTML To Fable Elmish

Fable uses functions to represent HTML elements and while this closely resembles HTML itself it does take a different form and at some point you’re going to want to convert a large piece of HTML to Fable.

That wouldn’t be fun, but fortunately you don’t need to do this by hand! There is an online tool available that you can post HTML into and out will pop the Elmish verison.

Alternatively this is also built into Ionide and you can do the conversion right their in Code:

Introducing Tailwind CSS

The SAFE template ships with Fulma for CSS – a F# wrapper for the Bulma CSS framework. However I’m already used to working with Tailwind (having moved away from Bootstrap) and I didn’t really want to learn / adopt another CSS toolkit so wanted to introduce this. Reasons why I like Tailwind are well articulated, not by me, here.

I confess I’ve not had any luck introducing it into the FAKE and webpack build chain for Fable. I’m certainly not an expert on either of those tools and so am likely hitting the limits of my knowledge rather than a fundamental issue (and were I not doing this project for fun I’d keep banging away until I’d solved it – but frankly other things to be doing!).

In the end I had to settle for a simple npx based approach that pre-generates the CSS. Not ideal but it works.

Routing / Endpoints

Creating endpoints is ridiculously simple in Saturn as you can see from this code:

let webApp = router {
    get "/api/init" (fun next ctx ->
        task {
            let counter = {Value = 42}
            return! json counter next ctx
        })

There’s no reason C# ASP .NET Core can’t be this simple (and in fact David Fowler recently posted an example of how it can be) but Microsoft have chosen the “way of pain” in most of their example code and templates and so ASP .NET Core code tends to, well, not be simple even for simple scenarios. In any case I appreciate the simple approach in the SAFE stack.

If you’ve made the journey from C# to F# you’ve probably gone through the same “wait… what… how…” in terms of the async changes. And there’s a fair chance that like me once you’ve figured the differences and what’s going on you’ve come to rather like the F# approach with its async { } computation expressions.

To ease interop with the rest of the .NET world Saturn uses a task { } block rather than F# async blocks. Practically speaking it doesn’t change much, for me at least, I prefer my domain code to be protocol agnostic and somewhat agnostic and so my Saturn endpoints are simple wrappers around functions which I continue to use async with.

Just caught me by surprise.

Serialization with Thoth

Under the covers SAFE is using Thoth to handle serialization. I’ve only just started to explore this. Mostly it seems to work as you’d expect just be aware that you need to return concrete collection types from routes. If you return a seq you’ll get an error like this at runtime:

Cannot generate auto encoder for Microsoft.FSharp.Collections.IEnumerator+mkSeq@132[[Shared.Api+Lift, Server, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. Please pass an extra encoder.

SQL Access

I’ve not done much SQL work from F# to date but I needed to in the context of the small project I’m building. I went scouting around for different ways of doing this and Twitter came to my rescue with a lot of suggestions.

In general I like to keep this simple and I don’t like DSLs in this space. I always find them a poor abstraction over SQL itself and one that simulatenously offers little value but a fair amount of risk: you have to second guess the SQL that is being generated. If I had a pound for every time I’ve been asked to fix performance issues that turned out to be due to this… well I’d have made enough to offset my stock market losses this week!

As a result with C# I generally use Dapper. There is a project that purports to wrap this in a F# friendly way in FSharp.Data.Dapper but it seems to have some pretty basic bugs (I couldn’t get it to run at all against SQL Server – open a connection first and it complains about that, don’t open a connection and it complains the connection is closed – I gave up). I was just about to write my own wrapper based on some work I did with Cosmos when I came across a handy gist:

I extended this with some async methods and that was me done.

In Summary

The F# community have created, and made very accessible, a fantastic set of tools that allow you to write F# end to end on the web and in a way that embraces the existing world and ecosystems rather than by trying to create its own new world (I’m looking at you Blazor). I’ve been able to take my F# knowledge and React knowledge and quite easily combine the two to be productive fast.

I’m looking forward to exploring this further over the next few weeks and will certainly write a new post as I learn more and as I find solutions for the things I currently have unresolved here.

App Service Easy Auth with Auth0 (or any Open ID Connect provider)

So I’m going to prefix this with a warning – I doubt this is officially supported but at a basic level it does seem to work. I would use at your peril and I’m writing this in the hope that it makes for a useful starting point discussion with the App Service team.

I was looking at Easy Auth this week and found myself curious as to if it would work with a generic Open ID Connect identity provider. My first choice provider is Auth0 but that’s not one of the listed providers on the Easy Auth configuration page which, on the face of it, is quite limited:

Azure AD is (as well as many other things) an Open ID Connect Provider so I had a look at its settings in the advanced tab and its asking for two pretty common pieces of information in the identity world: a client ID and an issuer URL. I had an app in Auth0 that I use for general testing so I pasted in its well known configuration endpoint and the ID for my client:

I hit save and it seemed to accept everything. My web app is sat on the URL https://jdreasyauth0.azurewebsites.net/ so on the Auth0 side I added a callback URL to the Easy Auth callback endpoint:

Easy Auth forwards on the contents of common claims in headers such as X-MS-CLIENT-PRINCIPAL-ID (the subject) and X-MS-CLIENT-PRINCIPAL-NAME (the name) so to see if this was working I uploaded a simple ASP.Net Core app that would output the contents of the request headers to a web page. Then I paid it a visit in my browser:

Oh. So that’s hurdle one passed. It does redirect successfully to a none-Azure AD identity provider. What about logging in?

Great. Yes. This works too. And the headers are correct based on the identity I used to login with.

How does this compare to the headers from an Azure AD backed Easy Auth:

Basically the Auth0 login is missing the refresh token (I did later set a client secret and tweak configuration in Auth0) – so there might be some work needed there. But I don’t think that’s essential.

It would be incredibly useful to be able to use Easy Auth in a supported manner with other identity providers – particularly for Azure Functions where dealing with token level authorization is a bit more “low level” than in a fully fledged framework like ASP .Net Core (though my Function Monkey library can help with this) and is only dealt with after a function invocation.

Using Function Monkey with MediatR

There are a lot of improvements coming in v4 of Function Monkey and the beta is currently available on NuGet. As the full release approaches I thought it would make sense to introduce some of these new capabilities here.

In order to simplyify Azure Functions development Function Monkey makes heavy use of commanding via a mediator and ships with my own mediation library. However there’s a lot of existing code out their that makes use of the popular MediatR library which, if Function Monkey supported, could fairly easily be moved into a serverless execution environment.

Happily Function Monkey now supports just this! You can use my existing bundled mediator, bring your own mediator, or add the shiny new FunctionMonkey.MediatR NuGet package. Here we’re going to take a look at using the latter.

First begin by creating a new, empty, Azure Functions project and add three NuGet packages:

FunctionMonkey
FunctionMonkey.Compiler
FunctionMonkey.MediatR

At the time of writing be sure to use the prerelease packages version 4.0.39-beta.4 or later.

Next create a folder called Models. Add a class called ToDoItem:

public class ToDoItem
{
    public Guid Id { get; set; }
    
    public string Title { get; set; }
    
    public bool IsComplete { get; set; }
}

Now add a folder called Services and add an interface called IRepository:

internal interface IRepository
{
    Task<ToDoItem> Create(string title);
}

And a memory based implementation of this called Repository:

internal class Repository : IRepository
{
    private readonly List<ToDoItem> _items = new List<ToDoItem>();
    
    public Task<ToDoItem> Create(string title)
    {
        ToDoItem newItem = new ToDoItem()
        {
            Title = title,
            Id = Guid.NewGuid(),
            IsComplete = false
        };
        _items.Add(newItem);
        return Task.FromResult(newItem);
    }
}

Now create a folder called Commands and in here create a class called CreateToDoItemCommand:

public class CreateToDoItemCommand : IRequest<ToDoItem>
{
    public string Title { get; set; }
}

If you’re familiar with Function Monkey you’ll notice the difference here – we’d normally implement the ICommand<> interface but here we’re implementing MediatR’s IRequest<> interface instead.

Next create a folder called Handlers and in here create a class called CreateToDoItemCommandHandler as shown below:

internal class CreateToDoItemCommandHandler : IRequestHandler<CreateToDoItemCommand, ToDoItem>
{
    private readonly IRepository _repository;

    public CreateToDoItemCommandHandler(IRepository repository)
    {
        _repository = repository;
    }
    
    public Task<ToDoItem> Handle(CreateToDoItemCommand request, CancellationToken cancellationToken)
    {
        return _repository.Create(request.Title);
    }
}

Again the only real difference here is that rather than implement the ICommandHandler interface we implement the IRequestHandler interface from MediatR.

Finally we need to add our FunctionAppConfiguration class to the root of the project to wire everything up:

public class FunctionAppConfiguration : IFunctionAppConfiguration
{
    public void Build(IFunctionHostBuilder builder)
    {
        builder
            .Setup(sc => sc
                .AddMediatR(typeof(FunctionAppConfiguration).Assembly)
                .AddSingleton<IRepository, Repository>()
            )
            .UseMediatR()
            .Functions(functions => functions
                .HttpRoute("todo", route => route
                    .HttpFunction<CreateToDoItemCommand>(HttpMethod.Post)
                )
            );
    }
}

Again this should look familiar however their are two key differences. Firstly in the Setup block we use MediatR’s IServiceCollection extension method AddMediatR – this will wire up the request handlers in the dependency injector. Secondly the .UseMediatR() option instructs Function Monkey to use MediatR for its command mediation.

And really that’s all their is to it! You can use both requests and notifications and you can find a more fleshed out example of this on GitHub.

As always feedback is welcome on Twitter or over on the GitHub issues page for Function Monkey.

Contact

  • If you're looking for help with C#, .NET, Azure, Architecture, or would simply value an independent opinion then please get in touch here or over on Twitter.

Recent Posts

Recent Tweets

  • An hour at 230 watts. Could have gone a bit harder. I suspect if I did a 20 min test I’d average 250 watts based on… https://t.co/No5JY2aXej
  • Can honestly say I’ve never been interrupted half way up the Passo Gavin to pick up a parcel before

Recent Comments

Archives

Categories

Meta

GiottoPress by Enrique Chavez