Dusted Codes

Programming adventures

Giraffe goes Beta

Giraffe Logo

After 6 months of working on Giraffe, lots of improvements, great community contributions and running several private as well as commercial web applications in production I am really happy to announce that Giraffe is finally going Beta. This might not sound like a big milestone to you, but given that I was very hesitant on pre-maturely labelling the project anything beyond Alpha and the many breaking changes which we had in the past it certainly feels like a big achievement to me! After plenty of testing, tweaking, re-architecting and some real world exposure I think we finally reached a point where I can confidently say that the external facing API will remain fairly stable as of now - and seems to work really well too ;).

What has changed

XmlViewEngine

Since the last blog post I have made several improvements to the previously known functional HTML engine, which has been renamed to a more generic XmlViewEngine now. The new changes allow the XmlViewEngine to be used beyond simple HTML views and can be used for things like generating dynamic XML such as SVG images and more. Personally I think the XmlViewEngine is the most feature rich and powerful view engine you can find in any .NET framework today and I will certainly dedicate a whole separate blog post on that topic alone in the near future soon.

Continuations instead of bindings

One particular big change which we recently had was the move from binding HttpHandler functions to chaining HttpFunc continuations instead. The HttpHandler function has changed its signature from a HttpContext -> Async<HttpContext option> to a HttpFunc -> HttpFunc, whereas a HttpFunc is defined as HttpContext -> Task<HttpContext option>.

The main difference is that a HttpHandler function doesn't return Some HttpContext any longer (unless you want to immediately short circuit the chain) and is responsible for invoking the next continuation function from within itself. If you think this sounds very similar to ASP.NET Core's middleware then you are not mistaken. It is the same concept which brings several benefits such as better control flow and improved performance.

Even though this posed a fundamental change in architecture, we didn't have to compromise on how easy it is to compose a larger web application in Giraffe:

let webApp =
    choose [
        GET >=>
            choose [
                route "/"       >=> renderHtml indexPage
                route "/signup" >=> renderHtml signUpPage
                route "/login"  >=> renderHtml loginPage
            ]
        POST >=>
            choose [
                route "/signup" >=> signUpHandler
                route "/login"  >=> loginHandler
            ]
        setStatusCode 404 >=> text "Not Found" ]

All credit goes to Gerard who worked on this big change entirely from concept to implementation on his own.

Tasks

Another architectural change was that Giraffe works natively with Task and Task<'T> objects now. Previously you would have had to convert from a C# Task<'T> to an F# Async<'T> workflow and then back again to a Task<'T> before returning the flow to ASP.NET Core, but not any longer.

If you paid close attention in the previous example then you might have noticed that a HttpFunc is defined as HttpContext -> Task<HttpContext option>. Apart from the additional convenience of not having to convert between tasks and asyncs any more, this change netted us a two figure % perf improvement overall.

From now on you can reference the Giraffe.Tasks module and make use of the new task {} workflow which will allow you to write asynchronous code just as easily as it was with F# async {} before:

open Giraffe.Tasks
open Giraffe.HttpHandlers

let personHandler =
    fun (next : HttpFunc) (ctx : HttpContext) ->
        task {
            let! person = ctx.BindModel<Person>()
            return! json person next ctx
        }

The original code for Giraffe's task implementation has been taken from Robert Peele's TaskBuilder.fs and minimally modified to better fit Giraffe's use case for a highly scalable ASP.NET Core web application.

Again, all credit goes to Gerard and his endless efforts in improving Giraffe's overall architecture and performance.

What to expect next?

Stability

First of all, as Giraffe has officially entered the Beta phase you can expect a much more stable API with no to minimal breaking changes going forward.

More performance

Next there are still many ways of improving the internals of Giraffe.Tasks which we think will yield even further perf improvements. Additionally Gerard plans to implement an alternative trie routing API which should promise another perf gain on web applications with large routing layers as well.

More sample applications and templates

Another area where I would like to focus on more in the future is in providing more sample applications and templates which will help people to get up and running with Giraffe in as little time as possible.

Also I would like to blog more about my own usage of Giraffe and show case a few production applications with a closer look at some stats, deployments and general tips & tricks.

I hope you like the latest changes and are still as excited about Giraffe as I am or even considering to build your next F# web application with the fastest functional .NET web framework you'll find anywhere today ;).

If you already use Giraffe for a commercial or hobby project please let me know in the comments below and I can feature you in the official GitHub repository if you like.

Thanks for reading and stay tuned until next time!

Comments

Functional ASP.NET Core part 2 - Hello world from Giraffe

This is a follow up blog post on the functional ASP.NET Core article from about two months ago. First of all I'd like to say that this has been the longest period I haven't published anything new to my blog since I started blogging in early 2015. The reason is because I have been pretty busy with a private project which I hope to write more about in the future, but more importantly I have been extremely busy organising my own wedding which took place at the end of last month :). Yes!, I've been extremely lucky to have found the love of my life and best friend and after being engaged for almost a year and a half we've finally tied the knot two weeks ago. Normally I don't blog about my private life here, but since this has been such a significant moment in my life I thought I should mention a few words here as well and let everyone know that the quiet time has been for a good reason and will not last for much longer now.

While this has primarily occupied the majority of my time I was also quite happy to see my functional ASP.NET Core project receive recognition from the community and some really great support from other developers who've been helping me in adding lots of new functionality since then. In this first blog post after my small break I thought I'd take the opportunity and showcase some of the work we've done since the initial release and explain some of the design decisions behind some features.

But first I shall say that the framework has been renamed to Giraffe.

ASP.NET Core Lambda is now Giraffe

ASP.NET Core Lambda was a good name in terms of being very descriptive of what it stood for, but at the same time there were plenty of other issues which led me and other people believe that a different name would be a better fit.

Initially I named the project ASP.NET Core Lambda, because, at its core it was a functional framework built on top of (and tightly integrated with) ASP.NET Core, so I put one and one together and went with that name.

However, it quickly became apparent that "ASP.NET Core Lambda" wasn't a great name for the following reasons:

As a result I decided to rename the project to something different and put the name up for a vote, which ultimately led to Giraffe. Looking back I think it was a great choice and I would like to thank everyone who helped me in picking the new name, as well as suggesting other great names which made the decision not easy at all.

I think Giraffe is a much better name now, because it is short, it is very clear and distinctive and there is no ambiguity around the spelling or pronunciation. There is also no other product called Giraffe in the .NET space and not really anything else which it could be mistaken with. The name Giraffe also hasn't been taken as a NuGet package which made things really easy. On top of that Giraffe gave lots of creative room for creating a beautiful logo for which I used 99designs.co.uk. I set up a design challenge there and the winner impressed with this clever design:

Giraffe Logo

Now I can only hope that the product will live up to this beautiful logo and the new name, which brings me to the actual topic of this blog post.

Overview of new features

There has been quite a few changes and new features since my last blog post and there's a few of which I am very excited about:

Dotnet new template

One really cool thing you can do with the new .NET tooling is to create project templates which can be installed via NuGet packages.

Thanks to David Sinclair you can install a Giraffe template by running the following command:

dotnet new -i giraffe-template::*

This will install the giraffe-template NuGet package to your local templates folder.

Afterwards you can start using Giraffe as a new project type when running the dotnet new command:

dotnet new giraffe

This feature makes it significantly easier to get started with Giraffe now. The quickest way to get a working Giraffe application up and running is by executing these three commands:

  1. dotnet new giraffe
  2. dotnet restore
  3. dotnet run

Everything should compile successfully and you should see a Hello-World Giraffe app running behind http://localhost:5000.

Nested routing

Another cool feature which has been added by Stuart Lang is nested routing.

The new subRoute handler allows users to create nested routes which can be very useful when logically grouping certain paths.

An example would be when an API changes it's authentication scheme and you'd want to group routes together which implement the same type of authentication. With the help of nested routing you can enable certain features like a new authentication scheme by only declaring it once per group:

let app = 
    subRoute "/api"
        (choose [
            subRoute "/v1"
                (oldAuthentication >=> choose [
                    route "/foo" >=> text "Foo 1"
                    route "/bar" >=> text "Bar 1" ])
            subRoute "/v2"
                (newAuthentication >=> choose [
                    route "/foo" >=> text "Foo 2"
                    route "/bar" >=> text "Bar 2" ]) ])

In this example a request to http://localhost:5000/api/v1/foo will use oldAuthentication and a request to http://localhost:5000/api/v2/foo will end up using newAuthentication.

There is also a subRouteCi handler which is the case insensitive equivalent of subRoute.

Razor views

Next is the support of Razor views in Giraffe. Nicolás Herrera developed the first version of Razor views by utilising the RazorLight engine. Shortly after that I realised that by referencing the Microsoft.AspNetCore.Mvc NuGet package I can easily re-use the original Razor engine in order to offer a more complete and original Razor experience in Giraffe as well. While under the hood the engine changed from RazorLight to ASP.NET Core MVC the functionality remained more or less the same as implemented by Nicolás in the first place.

In order to enable Razor views in Giraffe you have to register it's dependencies first:

type Startup() =
    member __.ConfigureServices (svc : IServiceCollection,
                                 env : IHostingEnvironment) =    
        Path.Combine(env.ContentRootPath, "views")
        |> svc.AddRazorEngine
        |> ignore

After that you can use the razorView handler to return a Razor page from Giraffe:

let model = { WelcomeText = "Hello World" }

let app = 
    choose [
        route "/" >=> razorView "text/html" "Index" model
    ]

The above example assumes that there is a /views folder in the project which contains an Index.cshtml file.

One of the parameters passed into the razorView handler is the mime type which should be returned by the handler. In this example it is set to text/html, but if the Razor page would represent something different (like an SVG image template for example) then with the razorView handler you can also set a different Content-Type as well.

In most cases text/html is probably the desired Content-Type of your response and therefore there is a second handler called razorHtmlView which does exactly that:

let model = { WelcomeText = "Hello World" }

let app = 
    choose [
        route  "/" >=> razorHtmlView "Index" model
    ]

A more involved example with a layout page and a partial view can be found in the SampleApp project in the Giraffe repository.

Using DotNet Watcher to reload the project on Razor page changes

If you come from an ASP.NET Core MVC background then you might be used to having Razor pages automatically re-compile on every page change during development, without having to manually restart an application. In Giraffe you can achieve the same experience by adding the DotNet.Watcher.Tools to your .fsproj and put a watch on all .cshtml files:

<ItemGroup>
    <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" />
</ItemGroup>
  
<ItemGroup>
    <Watch Include="**\*.cshtml" Exclude="bin\**\*" />
</ItemGroup>

By adding the watcher to your project file you can start making changes to any .cshtml file in your project and immediately see the changes take effect during a running Giraffe web application (without having to manually restart the app).

Dependency on Microsoft.AspNetCore.Mvc

One other thing which might sound a little bit strange is the dependency on the Microsoft.AspNetCore.Mvc NuGet package. It is essentially the full MVC library being referenced by Giraffe now and it has sparked a bit of confusion or disappointment amongst some users. Personally I think it really doesn't matter and I wanted to explain my thinking behind this design decision.

In order to get Razor views working in Giraffe there were three options available:

I certainly did not have an appetite for the first option, which is hopefully understandable, and therefore was left with the choice between the latter two.

At the time of writing there was only one .NET Core compatible custom Razor engine available, which is RazorLight. From what I know RazorLight is a very nice library and definitely highly recommended, but not necessarily the right choice for Giraffe.

When you ignore the name of the NuGet package for a second then there is really not much difference between referencing RazorLight or Microsoft.AspNetCore.Mvc in Giraffe. Both require a new NuGet dependency in the project and both are a library which exposes some functionality to render Razor views. The ASP.NET Core MVC package might be slightly bigger and offer more functionality than what Giraffe actually needs, but that doesn't really matter, because Giraffe ignores the rest and only uses what is needed for the Razor support. I think it is pretty normal that any given library often implements far more functionality than what a single project actually makes use of.

In the case of Giraffe I was faced with a trade-off between a dependency which uses slightly more KBs disk space, but in return offers a complete and original Razor experience vs. a slightly smaller library which offers a custom implementation of Razor pages.

As far as I see this issue there is absolutely no disadvantage in Giraffe using the MVC NuGet package in order to get the original Razor experience in comparison to using any other Razor library. I also believe that this option is more in line with Giraffe's goal to be tightly integrated with the original ASP.NET Core experience. Users benefit by getting the original, well documented and understood Razor features which makes portability of existing Razor views also significantly easier.

For me it's really about making smart choices and I truly believe that the strength of Giraffe is by standing on the shoulders of giants, which is ASP.NET Core MVC in this case.

Functional HTML view engine

Speaking of the Razor view engine, another really cool feature which has been added to Giraffe is a new programmatic way of creating views. Florian Verdonck helped me a lot with Giraffe over the last few weeks and one of his contributions was to port Suave's experimental Html engine to Giraffe.

I think the best way to describe the new Giraffe.HtmlEngine is by showing some code:

open Giraffe.HtmlEngine

let model = { Name = "John Doe" }

let layout (content: HtmlNode list) =
    html [] [
        head [] [
            title [] (encodedText "Giraffe")
        ]
        body [] content
    ]

let partial () =
    p [] (encodedText "Some partial text.")

let personView model =
    [
        div [] [
                h3 [] (sprintf "Hello, %s" model.Name |> encodedText)
            ]
        div [] [partial()]
    ] |> layout

let app = 
    choose [
        route "/" >=> (personView model |> renderHtml)
    ]

This examples demonstrates well how easy it is to create complex views with features like layout pages, partial views and model binding. There's really nothing that can't be done with this programmatic way of defining view-model pages and if you think there's something missing then it is really easy to extend as well.

Kudos to the Suave guys for coming up with this brilliant view engine and thanks to Florian for suggesting this feature as well as liaising with the Suave guys and porting the code to Giraffe!

Content negotiation

The next feature which I'd like to show off is something which I did myself for a change. When exposing a web service endpoint you often want to respect the client's requested response type which is typically communicated via the HTTP Accept header.

For example a client might send the following information with a HTTP Accept header:

Accept: application/xml,application/json,text/html;q=0.8,text/plain;q=0.9,*/*;q=0.5

In this example the client says the following:

In Giraffe you can use the negotiate and negotiateWith handlers to return the client the best matching response based on the information passed through the request's Accept header.

The negotiate handler is very simple and speaks JSON, XML and plain text at the moment:

[<CLIMutable>]
type Person =
    {
        FirstName : string
        LastName  : string
    }
    override this.ToString() =
        sprintf "%s %s" this.FirstName this.LastNam

let app = 
    choose [
        route  "/foo" >=> negotiate { FirstName = "Foo"; LastName = "Bar" }
    ]

By default the negotiate handler will check the request's Accept header and automatically serialize the model in either JSON, XML or plain text. If the client asks for plain/text then the negotiate handler will use the model's ToString() method otherwise it will use a JSON or XML serializer. Other mime types like text/html are not supported out of the box, because there is no default way to serialize an object into HTML.

However, if you want to support a wider range of accepted mime types then you can use the negotiateWith handler to set custom negotiation rules.

Let's assume you want to support two additional mime types, application/x-protobuf for Google's Protocol Buffers serialization and application/octet-stream for generic binary serialization.

First you would want to implement two new HttpHandler functions which can return a response of those exact types:

let serializeProtobuf x =
    // Implement protobuf serialization

let serializeBinary x =
    // Implement binary serialization

let protobuf (dataObj : obj) =
    setHttpHeader "Content-Type" "application/x-protobuf"
    >=> setBodyAsString (serializeProtobuf dataObj)

let binary (dataObj : obj) =
    setHttpHeader "Content-Type" "application/octet-stream"
    >=> setBodyAsString (serializeBinary dataObj)

Then you can use the two new HttpHandler functions to set up custom negotiation rules and use them with the negotiateWith handler:

let rules =
    dict [
        "*/*"                     , json
        "application/json"        , json
        "application/xml"         , xml
        "application/x-protobuf"  , protobuf
        "application/octet-stream", binary
    ]

let model = { FirstName = "Foo"; LastName = "Bar" }

let app = 
    choose [
        route  "/foo" >=> negotiateWith rules model
    ]

You might find it more convenient to create a new negotiate handler altogether, which will make it much less verbose to use the custom rules in subsequent routes:

let negotiate2 = negotiateWith rules

let app = 
    choose [
        route  "/foo" >=> negotiate2 { FirstName = "Foo"; LastName = "Bar" }
    ]

Even though there's still loads of room for improvement, I think this might be just enough for a large quantity of web applications already.

Model Binding

While the Accept HTTP header denotes what mime types a client understands (typically more than just one), the Content-Type HTTP header specifies which mime type a client/server has chosen to send a message with. This is very useful information when it comes to model binding.

Giraffe exposes five different model binding functions which can deserialize the content of a HTTP request into a strongly typed object. Four of them can bind a specific request type into a typed model and the fifth method picks the most appropriate model binding function based on the request's Content-Type header.

It's the easiest to demonstrate this with a quick example again. Let's assume we have the following record type in a web application:

[<CLIMutable>]
type Car =
    {
        Name   : string
        Make   : string
        Wheels : int
        Built  : DateTime
    }

Now I'd like to expose different endpoints which can be used to HTTP POST a car object to the web service:

open Giraffe.HttpHandlers
open Giraffe.HttpContextExtensions

let submitAsJson =
    fun (ctx : HttpContext) ->
        async {
            let! car = ctx.BindJson<Car>()			
            // Do stuff
        }
		
let submitAsXml =
    fun (ctx : HttpContext) ->
        async {
            let! car = ctx.BindXml<Car>()			
            // Do stuff
        }

let submitAsForm =
    fun (ctx : HttpContext) ->
        async {
            let! car = ctx.BindForm<Car>()			
            // Do stuff
        }
		
let submitAsQueryString =
    fun (ctx : HttpContext) ->
        async {
            let! car = ctx.BindQueryString<Car>()			
            // Do stuff
        }
	
let submitHowYouLike =
    fun (ctx : HttpContext) ->
        async {
            let! car = ctx.BindModel<Car>()			
            // Do stuff
        }
	
let webApp =
    POST >=>
        choose [
            route "/json"  >=> submitAsJson
            route "/xml"   >=> submitAsXml
            route "/form"  >=> submitAsForm
            route "/query" >=> submitAsQueryString
            route "/any"   >=> submitHowYouLike ]

As you can see from the example, the model binding functions are extension methods on the HttpContext object and require to open the Giraffe.HttpContextExtensions module.

The ctx.BindJson<'T>() function will always try to retrieve an object by deserializing data from JSON. The ctx.BindXml<'T>() function behaves the same way but will try to deserialize from XML. The ctx.BindForm<'T>() function will bind a model from a request which has a Content-Type of application/x-www-form-urlencoded (typically a POST request from a HTML form element).

Sometimes you might want to bind a model from a query string, which could not only come from a HTTP POST but also from any other HTTP verb request. In this instance the ctx.BindQueryString<'T>() function can be used to bind the values from a query string to a strongly typed model.

At last you might want to allow a client to submit an object via any of the above mentioned options on the same endpoint. In this case your endpoint has to pick the correct model binding based on the Content-Type HTTP header and this can be achieved with the ctx.BindModel<'T>() function.

Since all model binding functions are extension methods of the HttpContext type they can be used from anywhere in a web application where you have access to the HttpContext object, which in Giraffe's case is every single HttpHandler function.

What's next?

There were quite a few breaking changes since the first release, but APIs are slowly maturing as I get more feedback and exposure of the framework. So far the library has been in an alpha stage and will probably remain for another few weeks before I get around to finish some more examples and test projects which will eventually lead to the beta phase.

Once the project is in beta I will try to focus my effort more on collecting a lot of additional feedback before I feel confident enough to declare the first RC and subsequently the official version 1.0.0.

Even though breaking changes are not always the end of the world I would like to avoid drastic fundamental changes (as seen recently) once the project has entered the first stable release. Therefore I have been fairly reluctant to prematurely label Giraffe beyond an alpha and will probably want to enjoy the freedom of breaking stuff for a tiny bit longer. At the end of the day it's about setting the right expectations and I don't help anyone by labeling v1.0.0 too early when I know there's still a fair bit of danger to potentially move stuff around.

However, having said that I do want to stress that the underlying system (ASP.NET Core and Kestrel) have been very stable for a while now and as long as you don't mind that a namespace or method might still change in the near future then Giraffe is absolutely fit for production. So please go ahead and give it a try if you like what you've seen in this blog post so far :).

This basically brings me to the end of this follow up article and I thought what better way to finish it off than by sharing some of our memories from our wonderful wedding (in case you ever wondered what a British-Indian/Austrian-Polish wedding looks like ;)).

It was a very long day, which started off with a civil ceremony in the morning...

Civil ceremony in the morning of the day

Followed by a traditional Hindu ceremony shortly after lunch...

Drums during groom entrance at Hindu ceremony

Groom entrance at Hindu ceremony

Prayers at Hindu ceremony

Listening to Hindu priest cracking jokes

I had no idea how much fun Hindu ceremonies can be! There's lots of really fun and merry traditions which take place as part of us getting married. Then there's also a bit of banter between the two families. One of those little traditions is that the bride's family has to steal the groom's shoes before the ceremony ends so that the groom can't leave the house and take his newly wedded wife away from her family - at least not without having to pay for getting his shoes back. Normally this results in a bit of shoe pulling between the bride's side and the groomsmen, but I think in our case it is fair to say that there was a bit of a cultural clash when someone from my family rugby tackled a guy who tried to sneak away with my shoes, lol...

Shoe fight

Luckily nothing serious happened and after everyone had a great laugh we continued with the ceremony...

Until finally we were able to celebrate at the reception party in the evening...

Entering at the reception party

Cake cutting

Our first toast as a married couple

Throughout the day our guests wrote us lovely (I think) messages on little papers and my family decided to throw all these messages into a wooden box with a nice bottle of Red, which we had to seal ourselves with nails and hammer. We are not allowed to open this box until in seven years time and then we can enjoy a nicely matured bottle of vino while reading all those wonderful memories from our big day. What a brilliant idea!

Sealing box of memories

We had a fantastic day and before everyone stormed to the dance floor there was even a pretty impressive surprise firework display...

Surprise firework display

Getting married was a lot of fun and it all worked out so much better than we could have hoped for :)

Now we are ready for new adventures...

Comments

Older Posts