This post is the first part in a short series on programming web-enabled, functional-friendly applications in F# and has kindly been written by Krzysztof Cieślak. Thanks, Chris!
For many developers, Functional Programming (FP) is not only more difficult to learn, but developers also often believe that it's difficult to find any real world applications using it. However, FP gives developers the benefits of terse code, precise expressiveness and a better type system, whilst FP also works particularly well with concurrent programming.
Now, compare it with the following example function using a simple set of F# types.
F# is a mature, open source, cross-platform, functional-first programming language. It empowers users and organizations to tackle complex computing problems with simple, maintainable and robust code.
F# has several important features that make it a great choice for web programming:
asyncworkflows make it very easy to write asynchronous code, which simplifies writing scalable, reactive web applications
Suave is a simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition
Suave is probably the most popular F# library for the web programming. It provides a lightweight, non-blocking web server, and a set of functions and combinators that let developers represent the logic of their web application as a set of functions that are composed together.
Here's an example of "hello world" in Suave:
1: 2: 3:
The building block of all Suave applications is the WebPart. A WebPart is simply any F# function (no magic involved!) that aheres to the following signature
HttpContext -> Async<HttpContext option> - here's an example function that returns Hello World that happens to be a webpart. There's no need to implement an interface or inherit from a base class - simply matching this signature is enough to participate in the Suave engine.
As you can see, a WebPart is any function that takes an
HttpContext (an object containing the HTTP request, response, and any other required data e.g. headers), and tries to asynchronously return a new
HttpContext. It's important to notice that WebPart can also return
None - which means that the operation failed. Here's a sample WebPart:
1: 2: 3: 4: 5: 6:
Having a single WebPart is normally not enough for any reasonably sized application - no one wants to write their whole application as a single function! So, Suave also introduces the idea of combinators - functions that can combine multiple WebParts into a single WebPart - and this combination can be both vertical and horizontal.
The two most important combinators are:
>=>- Used to chain (or compose) multiple WebParts together. It runs the first WebPart, waits for it to finish, and then if it returned
Some HttpContext, passes it to next WebPart as an input. If the first part failed and
Nonewas returned, the entire WebPart will immediately
Nonewithout executing second part. If you're familiar with Scott Wlaschin's series on Railway Oriented Programming, this idea of "two track" programming should be immediately familiar to you.
choose- a function that takes a list of WebParts and combines them all into single WebPart. This new webpart executes each individual WebPart in turn, until if finds one of them that returns success, which becomes the overall result.
Here's a sample of using Suave's combinators:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
We first write a simple function,
greetings, which takes in some bag of key/value pairs. We then try to retrieve the
name value from the bag, and if none is found, replace it with the default of "World". We then return that as a string e.g. "Hello, World" or "Hello, Chris".
The second function is the main WebPart which will represent our web server. It combines a moderately complex set of routes into an easy-to-read form:
greetingsusing the query string as the bag.
greetingsusing the form object as the bag.
Observe how closely this flow diagram fits with the actual code:
This model offers an excellent way to write simple code using basic F# functions, and then compose them together using Suave's powerful combinators in a stateless manner into complex applications - a great use of F# and FP principles. No interfaces, no inheritance, and no heavyweight libraries or frameworks needed.
Suave is not only F# library for the server-side web programming (although it's arguably the most popular, with the biggest community support). There also exist other options for creating web applications with F#:
Giraffe - an F# micro web framework for building rich web applications. It has been heavily inspired and is similar to Suave, but has been specifically designed with ASP.NET Core in mind and can be plugged into the ASP.NET Core pipeline via middleware. Giraffe applications are composed of so called HttpHandler functions which can be thought of a mixture of Suave's WebParts and ASP.NET Core's middleware.
Freya - a functional web stack built on top of OWIN. At its core, Freya wraps the OWIN environment dictionary with a computation expression and provides access to that dictionary with lenses. Additional layers of the stack provide types based on the HTTP (and related) RFCs, a pipeline abstraction for connecting Freya computations, a router, and an implementation of the HTTP finite state machine
WebSharper - allows end-to-end web applications with both client and server developed in F#. It includes TypeScript interoperability, mobile web apps, getting started material, templates and much more.
Azure Functions - an event driven, compute-on-demand experience that extends the existing Azure application platform with capabilities to implement code triggered by events occurring in Azure or third party service as well as on-premises systems. Developers can leverage Azure Functions to build HTTP-based API endpoints accessible by a wide range of applications
In this post, I've tried showing how FP and F# in particular can be a great, natural fit for web programming. I've described several properties of FP that makes it easy to create web applications, and shown that any web server can be treated as a simple function taking HTTP request and returning an HTTP response. I've also shown how F# fits into this picture and what language features make it a great choice for building web applications. Finally, I've shown Suave - a native F# library that uses a unique programming model that lets developers create complex web server applications by combining simple, reusable functions.