Suave.IO introduction and example - Part 2: Setting up a project

Suave.IO introduction and example - Part 2: Setting up a project

-

OK, we are ready to get started, the first thing we need to do is set up a new Suave project and run it locally on our own machine. But before we can do that, we need to make a decision.

Script or project?

We have two options when we want to create a new Suave-based application. We can either boot up Visual Studio and create a new F# application, or we can take a simpler approach and create our application using F# scripting.

Over at the official Suave.IO website you will find an example of a completely self-contained script-based Suave application.

There are pros and cons, as always, but when deciding which route to take there are a few things to consider, like how you want to run the application, and how large you expect it to become.

I find that starting out with a script-based application allows you to get going quickly and start experimenting. If you later decide that you want to turn it into a "proper" application (maybe you want it running stand-alone, or as a service), converting it shouldn't be that much of a hassle.

For this example we will write our application as a script and use the build system FAKE to run it.

I was introduced to this approach when I attended a workshop by Tomas Petricek. The same approach is used by Scott Hanselman in his blog post Running Suave.io and F# with FAKE in Azure Web Apps with Git and the Deploy Button.

I will be borrowing heavily from both as this example unfolds.

Understanding our foundation

Now we have decided to write our application as a script, and I've mentioned running it using FAKE. Let's add Paket to the mix as well and discuss the basics before we get started with our application.

FAKE

FAKE is short for F# Make, and is a build system that allows us to use F# scripts as build configurations. This is convenient for us because we can use FAKE to run and host our Suave application (which is plain old F# scripts).

Paket

Paket is an alternative to Nuget, providing us with a way of getting hold of our application dependencies. It plays nice with Nuget-packages and adds some nice additional features. Could we have used Nuget for this example? Yes, absolutely, for a small example application like this, the advantages of using Paket aren't obvious.

I have chosen to use Paket because I think the F# community is leaning towards it, and because I think the improved control over dependencies and versioning provided by Paket becomes relevant when you go from an example to a real world application.

If you want additional information about Paket, check out the official website and their FAQ.

Getting the files from GitHub

You can either write the application as we go along, your you can go and grab the code from my GitHub account.

The basic project files

The first thing we need to do is to create a new folder for our project. We want to write a tiny todo-app using Suave, so let's try to find a creative name for it. How about "suave-todo"? Perfect!

Load the folder up in your favourite code editor (I am experimenting with Visual Studio Code at the moment) and add the following files. We will take a look at each in turn afterwards.

  • local.cmd
  • dependencies.cmd
  • paket.dependencies
  • build.local.fsx
  • app.fsx

New Suave project files

local.cmd

I haven't mentioned it until now, but this example is targeted towards running Suave.IO in a Windows environment. The local.cmd batch file is our starting point while we develop the application. We want to be able to install dependencies and have the application running locally just by running the local.cmd in Powershell.

.\local.cmd 

The contents of the batch file is quite simple. First we want to install dependencies, and then we are ready to run our application using FAKE by invoking it with our "build.local.fsx" script.

@echo off

call dependencies.cmd

@echo "Running web server"
packages\FAKE\tools\FAKE.exe %* --fsiargs build.local.fsx

dependencies.cmd

What sort of black magic goes on to install our dependencies? Well first of all we need to install Paket so we can start grabbing our dependencies from Nuget. Thankfully Paket comes with a handy tool called the Paket bootstrapper, that allows us to do this in a quick and easy way.

@echo off
cls

if not exist .paket (
  @echo "Installing Paket"
  mkdir .paket
  curl https://github.com/fsprojects/Paket/releases/download/1.4.0/paket.bootstrapper.exe -L --insecure -o .paket\paket.bootstrapper.exe

  .paket\paket.bootstrapper.exe prerelease
  if errorlevel 1 (
    exit /b %errorlevel%
  )
)

if not exist paket.lock (
  @echo "Installing dependencies"
  .paket\paket.exe install
) else (
  @echo "Restoring dependencies"
  .paket\paket.exe restore
)

The script above does two things. First it grabs the bootstrapper executable directly from the Paket project GitHub, then it runs it on your machine to install Paket.

You understand the security ramifications of grabbing an executable from a server and running it locally, whether or not this is something you want to be doing is up to you. It is veryyy convenient though!

After having successfully installed Paket we can now either install our dependencies or just restore missing dependencies, based on whether this is the first time we run Paket or not.

When all is done, we now have our dependencies ready to use. So what are these dependencies.

paket.dependencies

To answer that, let's take a look at the Paket dependency definition file.

source https://nuget.org/api/v2

nuget FAKE
nuget Suave
nuget FSharp.Compiler.Service

There are two important things in here, FAKE and Suave, this is all we need think about for now. The actual Suave library, and FAKE to run our application for us. The FSharp.Compiler.Service library is used by our build script.

build.local.fsx

With our dependencies in place we are now ready to use FAKE to run our local build script. You remember the last line from local.cmd

packages\FAKE\tools\FAKE.exe %* --fsiargs build.local.fsx

The purpose of the build script is basically to configure our Suave webserver and point it at our application. It could have looked something like this.

#r "packages/Suave/lib/net40/Suave.dll"
#r "packages/FAKE/tools/FakeLib.dll"
#load "app.fsx"
open App
open Fake
open System
open System.IO
open Suave
open Suave.Http
open Suave.Web
open Suave.Types

let serverConfig =
    let port = int (getBuildParam "port")
    { defaultConfig with
        homeFolder = Some __SOURCE_DIRECTORY__
        logger = Logging.Loggers.saneDefaultsFor Logging.LogLevel.Warn
        bindings = [ Types.HttpBinding.mk' Types.HTTP "127.0.0.1" port ] }

Target "run" (fun _ ->
    startWebServer serverConfig app
)

RunTargetOrDefault "run"

In this simple example we first reference both Suave and FAKE. We then load our own application which we will look at next. After opening the modules required we create the configuration for the webserver and run it.

However, this is not what our local build script looks like. Instead we will use a build script by Tomas Petricek. This build script monitors the application folder for changes and restarts the webserver when files are updated. Very convenient when we are working on our application.

I've asked for permission to include the build script, but have cut out some parts that I am not using for this example. I've also added a small snippet that I will return to in a later post.

When the script is run a webserver will start serving our app at localhost:8083, and reload our application when we make changes.

app.fsx

That leaves us with our actual application. For now I think it's enough to just return a 200 response and a bit of text.

#r "packages/Suave/lib/net40/Suave.dll"

open Suave
open Suave.Web
open Suave.Http.Successful

let app = OK "Welcome to the todo app"

The "app" value is the starting point for our application, this is what we told our build script to start serving. From our build.local.fsx:

// "app" is defined in app.fsx which we reference in the build script
startWebServer serverConfig app

What we are basically telling our webserver is this: When you get a request, always return Suave.Http.Successful.OK (which is 200 response with the text "Welcome to the todo app".

Running it

That's all we need to run our application. Let's take it for a spin by opening powershell and running ./local.cmd.

First run of our Suave app

Since this is the first time we run it, we are going through all the steps we've discussed above.

  1. Download and install Paket
  2. Use Paket to install dependencies, including FAKE
  3. Use FAKE to start a webserver and start serving our application.

The build script opens a browser window at http://localhost:8083, which looks like this.

First run of our Suave app in the browser

Awesome! We are now running a Suave application locally by running a single command. Now we can turn our attention to the interesting stuff, like our actual application!

Let's actually do something

This post is part of a larger series where we set up a minimal Suave.IO application. In the next chapter Part 3 - Requests and routing we will see how we start serving some actual content!

View Comments