FP Complete


One of our primary goals when designing the School of Haskell was making it convenient to write up tutorials on web development. As I’m sure many people can guess, I personally think that web development is an important domain to give proper coverage to. And for those of you on our beta program, you’ve probably already seen that this web support extends to our IDE as well.

Since we’ve published a few tutorials on using Yesod, some people got the impression that our system supported only one web framework. I’m here to tell you that, on the contrary, we have first class support for the two other most popular Haskell web frameworks and, in addition, explain how our system supports web applications, and why we made the technical decisions we did.

So let’s get started easily. Mike Meyer, our senior support engineer, has written up a very straight-forward tutorial (defunct) demonstrating how to run Snap and Happstack applications in the SoH. The short description is that we provide a package called web-fpco that provides some wrapper functions to launch your code in our environment. The FP Haskell Center (FPHC) library set provides a full complement of Happstack and Snap dependencies, so you should be able to just change a few import statements and run your existing applications on our system.

But that really begs the question: what’s the magic behind the scenes? The only real trick is that we need to know which port the application will receive HTTP requests on, and then set up reverse HTTP proxying to forward requests from the outside world to that user application. One approach would be to standardize on some specific port number, or allow the user to annotate a program to let FPHC know which port to reverse proxy to. However, that leads to two issues:

Instead, we went with the opposite approach: FPHC sets the PORT environment variable when running user code to tell the application which port number it should listen on. This is a technique I’ve used in that past, and is how both the Yesod development server and the Keter deployment system work. (And yes, we could bikeshed on the actual name of the environment variable…) So if you look at the source code for web-fpco, you’ll notice that all it does is check for the PORT variable and then call out to the standard functions for Snap and Happstack.

FPHC sets one additional environment variable: APPROOT gives the base URL for the application, so that you can generate absolute URLs from your application. The approot consists of the scheme and domain name; for FP Complete’s main site, the approot would be https://www.fpcomplete.com (note the lack of trailing slash).

There was one other approach I considered (I think Gregory Collins first mentioned it to me): systemd style socket activation. Essentially, FPHC would create a listening socket for the application, dup2 it to a well-known file descriptor like 3, and then start the application, which would then start accepting connections from that file descriptor. There are a few reasons we ended up going with the PORT environment variable approach instead:

I think our system makes it easy to get up and running with web development in Haskell. And since the underpinnings are so simple, it would even be possible to develop your own web server on FPHC. As a trivial example, here’s a network-conduit-based snippet that will answer a single HTTP request.

{-# LANGUAGE OverloadedStrings #-}
import Data.Conduit
import Data.Conduit.Network
import System.Environment

main :: IO ()
main = do
    port <- fmap read $ getEnv "PORT"
    runTCPServer (serverSettings port HostAny) $ appData -> do
        appSource appData $$ await -- grab and ignore the request from the client
        yield "HTTP/1.0 200 OKrnContent-Type: text/plainrnrnHello World!!!rn"
            $$ appSink appData

Subscribe to our blog via email

Email subscriptions come from our Atom feed and are handled by Blogtrottr. You will only receive notifications of blog posts, and can unsubscribe any time.