Using the warp HTTP server, I want to handle HTTP query parameters.
It's easy (see for example here) to make Warp render something for URLs like
http://localhost:3000/foo
How can I make it render
http://localhost:3000/foo?id=bar
in a way where the content is dependent on the id
query parameter?
Additionally, how can I handle if there is no such parameter?
I'll build my example on this previous answer.
The most important module in this context it Network.HTTP.Types
, specifically the Query
type.
You can get a Query
from a WAI Request
using QueryString
.
As a Query
is nothing more than a [(ByteString, Maybe ByteString)]
, we can use lookup
from the base library to find the appropriate attribute.
However, as lookup
wraps the type in a Maybe
itself, we end up witha Maybe (Maybe ByteString)
. My example contains the rather ugly-sounding function maybeMaybeToMaybe
to convert this to a Maybe ByteString
.
The example returns a plaintext response (on any URL) that contains the id
query parameter. As it just uses show
, for the example URL
http://localhost:3000/foo?id=bar
it yields
Query parameter: Just "foobar"
whereas for
http://localhost:3000/
it yields
Query parameter: Nothing
Here's the full source code:
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative ((<$>))
import Control.Monad
import Network.Wai
import Network.Wai.Handler.Warp
import Network.HTTP.Types (status200)
import Network.HTTP.Types.Header (hContentType)
import Blaze.ByteString.Builder.Char.Utf8 (fromString)
import Data.ByteString (ByteString)
main = do
let port = 3000
putStrLn $ "Listening on port " ++ show port
run port app
app req f = f $
case pathInfo req of
-- Place custom routes here
_ -> anyRoute req
anyRoute req =
let query = queryString req :: [(ByteString, Maybe ByteString)]
idParam = join $ lookup "id" query :: Maybe ByteString
in responseBuilder
status200
[(hContentType, "text/plain")]
$ fromString $ "Query parameter: " ++ (show idParam)