Skip to content

SamuelSchlesinger/porpoise

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Porpoise

Hackage

Saving the Finless Porpoise

An extremely minimal, unopinionated framework for building HTTP servers built over the wai server interface.

This framework is unopinionated, but here is the sort of structure I would recommend while using it:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE BlockArguments #-}
module Main where

import Prelude hiding (id, (.))
import Data.ByteString (ByteString)
import Web.Porpoise
import Data.Text (Text)
import Data.Aeson (Value)
import Control.Monad.IO.Class (liftIO)
import Network.Wai.Handler.Warp (run)

data Command =
    HealthCheck
  | NoMatch

main :: IO ()
main = run 8080 $ toApplication (processCommand . requestCommand)

requestCommand :: Server IO Request Command
requestCommand = do
  r <- id
  body <- liftIO $ lazyRequestBody r
  pure $ case (requestMethod r, pathInfo r, queryString r, body) of
    ("GET", ["health"], [], "") -> HealthCheck
    _ -> NoMatch

healthy204 :: Status
healthy204 = mkStatus 204 "Healthy"

some404 :: Status
some404 = mkStatus 404 "Not Found"

allContentTypes :: (ByteString, ByteString)
allContentTypes = ("Content-Type", "*/*")

emptyBody :: ByteString
emptyBody = ""

processCommand :: Server IO Command Response
processCommand = id >>= pure . \case
  HealthCheck ->
    responseBuilder healthy204 [allContentTypes] emptyBody
  NoMatch ->
    responseBuilder some404 [allContentTypes] emptyBody

This framework is not a silver bullet. In particular, when you have a typical HTTP application, you probably want to use something like servant. But lets say you are porting an old service over from some other language to Haskell, and you can't leverage the existing server combinators in servant, then this is an alternative to writing it by hand in wai, giving the Server type which reveals some of the nice structure inside of the wai concept of a Server.

What you shouldn't do is use Server for all of your code, necessarily. It does not have an instance of MonadUnliftIO, and your server code should almost certainly be written in a type that can have an instance for that class. This library is meant to form the top, infrastructural layer of a server program, and allow for certain types of control flow at that layer, such as the use of callCC.

About

A simple web framework built on top of wai

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published