Serving Html with Suave and Liquid

Matthew Doig
5 min readDec 13, 2016

--

Most tutorials about Suave focus on using it for building RESTful web services, but we can of course use Suave for the more pedestrian task of serving up regular ol’ html pages.

There’s a poorly documented blip on the home page about using the Liquid templating engine for serving html, so let’s flesh that blip out and actually get something resembling a web app rendering in our browser.

What is Liquid ?

I must confess to being blissfully unaware of Liquid, as it tends not to garner the mindshare in the developer community of React/Angular/Elm, but there’s a vibrant community around the technology, using it to sell millions of products a day.

Created by Shopify, Liquid is a

Safe, customer facing, template language, for creating dynamic web apps

The language is open source, well documented, with tons of themes to choose from.

And it’s not just for Shopify themes, Jekyll is a simple blog aware site generator, that doesn’t require a database, and can be hosted on Github.

So although Liquid may not have, dare I say the hype of other frameworks, it’s open source, on release 3.0, with tons of users, and a solid record of solving problems. The perfect complement to Suave!

Hello Liquid

As I said, the documentation around using Liquid with Suave is barebones, and the “example” even barer. So instead, we’ll use the sample from the Liquid Github repository and retrofit it to work with Suave.

First, crack open VS Code and create a Suave application named MyShop, if you haven’t setup one before, see this article to get going.

Now that we have a Suave application setup, we’ll add a reference to DotLiquid, the .Net port of Liquid.

  • Open MyShop.fsproj in the VS Code Editor
  • ⌘ + Shift + P to open the command pallette
  • Paket: Add Nuget Package (to current project)
  • Type DotLiquid as the package name
  • Do the same for Suave.DotLiquid
  • Create a folder named Templates in the root
  • Add a file named index.liquid and add the following code
<h1>{{model.title}}</h1>
  • Update our MyShop.fs file to the following
open Suave
open Suave.Filters
open Suave.Operators
open Suave.DotLiquid
open DotLiquid
type Model = { title : string }setTemplatesDir “./../templates”let o = { title = “Hello World” }let app =
choose [
path “/” >=> choose [
GET >=> page “index.liquid” o ]]
startWebServer defaultConfig app
  • ⌘ + F5 does a build

However, when we try to run our sample we get the following message

bash-3.2$ cd build
bash-3.2$ mono HelloLiquid.exe
System.IO.FileNotFoundException: Could not load fil
e or assembly 'DotLiquid, Version=1.8.0.0

For some reason DotLiquid doesn’t target the 4.5 framework, so a quick fix to the target framework in MyShop.fsproj

<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>

And we get a big bold HelloWorld in our browser when we browse to our server.

Basically, we tell DotLiquid where our templates are, create a record to hold our data, and use the awesome Suave combinators to declaratively serve up a template with the requisite record.

Installing a Liquid VS Code Extension

Before we add more templates to our app, we’ll install the following Liquid extension for VS Code to get syntax highlighting for our templates.

VS Code rocks, cross language, cross platform, lightweight, and community driven, sort of the antithesis of Visual Studio Professional, which seems stuck in the dark ages of Microsoft’s Windows world order school of tooling over concepts programming.

Adding Products to our Shop

Our shop is working, yet it’s a tad barren without any products to show off.

These samples are a bit longer, so I’ll switch to using Gists for the code. I’m still unsure whether it’s best to use gists or “code blocks” here on Medium for showing code. The big problem with gists is they don’t show inline in the Medium app on mobile devices, but once a code file gets longer then it’s nearly unreadable in code blocks. Maybe I’ll take a look at Jekyll!

Update our index.liquid template to the following.

Add an all new template named products.liquid so we have something to sell.

And update our MyShop.fs file to the following.

Forget everything else in the code above and simply look at the app function. Notice how simple the routing in our app is to read? I love how declarative and readable Suave.io is compared to MVC and other web frameworks I’ve used.

Aside from the great routing, we can easily extend Liquid with server side filters that let us modify and massage our output. Again, we get the full expressiveness of F# and the breadth of the .Net api when formatting our output for display.

If you run the app now then you’ll see a list of products we have for sale in our shop.

A Few Little Gotchas

There are a few little gotchas to be aware of when serving up our templates.

  • The registerFiltersByName function doesn’t work from the Suave.DotLiquid.dll so we’ve created a version of the function to run in our MyShop.exe dll. Not sure if this is mono related, but for some reason Assembly.GetEntryAssembly returns null when running from a separate assembly.
  • We can’t use generic functions. You’ll notice that there is a commented out version of the count function that will work for any List, however, DotLiquid doesn’t support runtime reification of generic functions and fails to find a match for List<Product>.
  • Concat is not support by DotLiquid but is supported by Liquid. There are a few functions that have not been ported to DotLiquid and so using Liquid templates may require you to roll a few functions of your own in order to get them working.

Raking in the Millions

So now that you see how easy it is to serve up Shopify Liquid templates from Suave.io, go build your shop and become the next Jet.com!

--

--

Matthew Doig

A programmer looking for ways to see the forest instead of the trees.