Web Application in Haskell

This publication will introduce you into development process of web application with usage of Haskell programming language. I would like you to have a clue about “How does the internet work?” and “What is HTTP?” before we will proceed into intial chapter.

Iterative server loop

In casual web (application) development you would rather choose a library with would abstract this mechanism away, althrough it’s not very complicated when we strip away in-depth knowledge about how servers work with TCP sockets.

create socket
bind(address, port)
listen()

while true:
    conn, client_addr = accept()
    handle(conn) # then close

That is the classic iterative server loop. Everything else (threads, async, frameworks) is just a way to handle the connections more efficiently.

Implementation

We use Network.Socket, Network.HTTP, and Network.URI libraries which are considered low-level packages and are necessary to implement iterative server loop directly.

module Main (main) where

import Control.Monad (forever)
import Network.HTTP
  ( Request(rqURI)
  , Response(..)
  , close
  , receiveHTTP
  , respondHTTP
  , socketConnection
  )
import Network.Socket
  ( Family(AF_INET)
  , SocketType(Stream)
  , SockAddr(SockAddrInet)
  , accept
  , bind
  , defaultProtocol
  , listen
  , socket
  , tupleToHostAddress
  )
import Network.URI (uriPath)

main :: IO ()
main = do
  lsock <- socket AF_INET Stream defaultProtocol
  bind lsock (SockAddrInet 8080 (tupleToHostAddress (0, 0, 0, 0)))
  listen lsock 1
  forever $ do
    (csock, _) <- accept lsock
    hs <- socketConnection "" 8080 csock
    req <- receiveHTTP hs
    case req of
      Left _  -> close hs
      Right r -> do
        let path = uriPath (rqURI r)
            resp
              | path == "/" = Response (2,0,0) "OK"        [] "Hello, World!\n"
              | otherwise   = Response (4,0,4) "Not Found" [] "Nothing here\n"
        respondHTTP hs resp
        close hs

It’s a simple web application you could ever seen which greets a user when access through HTTP with "Hello World".

Running the application

To run this application, you will need a local Haskell development environment with Cabal installed.

Cabal file

Create a haskell.cabal file in your project root with the following configuration:

cabal-version:      3.0
name:               haskell
version:            0.1.0.0
license:            BSD-3-Clause
license-file:       LICENSE
author:             keinsell
maintainer:         [email protected]
build-type:         Simple
extra-doc-files:    CHANGELOG.md

common warnings
    ghc-options: -Wall

executable haskell
    import:           warnings
    main-is:          Main.hs
    build-depends:
        base ^>=4.21.0.0,
        network ^>=3.2.8.0,
        HTTP ^>=4000.4.1,
        network-uri ^>=2.6.4.2
    hs-source-dirs:   app
    default-language: Haskell2010

Key takeaway: The main entry point is expected at app/Main.hs, and the four low-level libraries (base, network, HTTP, and network-uri) must be specified under build-depends.

Manually test your application

Initialize and launch the server application directly through Cabal:

cabal run

Once the server is running, open a separate terminal window to test the endpoints:

curl http://localhost:8080/
# Output: Hello, World!

curl http://localhost:8080/foo
# Output: Nothing here

There’s a long way ahead.

There’s a lot of what we didn’t touched and what have been showed up there is a drop of a water in the sea of what is left unsaid there.

The next phase involves implementing routing and configuring HTML page rendering, until introduction of usage of major libraries.

Back to Blog