joncfoo

Spock - Query Parameters

Posted on 2017-11-24

This literate haskell file demonstrates how to use query parameters with Spock. A copy of this runnable file is available here. You may run it via stack with the following command:

stack --resolver lts-9.14 runghc --package Spock SpockParam.lhs

Extensions

{-# LANGUAGE OverloadedStrings #-}

Imports

import Data.Monoid ( (<>) )
import Web.Spock
    ( SpockM, runSpock, spock, get, text
    , param
    , param'
    )
param reads a request parameter (first from POST variables and then GET query parameters)
param' like param above but throws an error if the request parameter is missing
import Web.Spock.Config
    ( PoolOrConn (PCNoDatabase)
    , defaultSpockCfg
    )

Data types

data AppSession = EmptySession
data AppState = EmptyState

Web application definition

webapp :: SpockM () AppSession AppState ()
webapp = do
   get "hello" $ do
       mName <- param "name"
       case mName of
           Nothing ->
               text ("Hello stranger!  Sorry, I did not get your name.")
           Just name ->
               text ("Hello " <> name <> "!  Nice to meet you.")

The route above handles GET /hello and looks for a query parameter named name. Note that we are forced to handle the absence of the name query parameter since param returns a Maybe.

Try visiting:

   get "howdy" $ do
       name <- param' "name"
       text ("Howdy " <> name <> "!  How goes it?")

This last route handles GET /howdy and requires the name query parameter to be present.

Try visiting:

Main

main :: IO ()
main = do
    defConfig <- defaultSpockCfg EmptySession PCNoDatabase EmptyState
    runSpock 5000 (spock defConfig webapp)

Notes

param and param' have a Typeclass constraint of FromHttpApiData. This means that you can use param and param' for any type that has instances of FromHttpApiData including your own! For the full list of types that have instances of FromHttpApiData check the docs here.

Exercises

  1. (Easy) Add a route GET /add that takes two query parameters x and y and responds with the the sum of the two numbers.

  2. (Medium) Change the above route to return a nice/helpful message when one or both parameters are missing. Hint: use the Maybe monad to avoid having nested pattern matching.

  3. (Easy/Medium) Add a few routes which take different types of query parameters — e.g. Bool, Double, Natural, UTCTime.

    • Hint: have a look at FromHTttpApiData mentioned in the Notes.