2

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?

How to deliver JSON over HTTP using Warp with Aeson

Community
  • 1
  • 1
Uli Köhler
  • 13,012
  • 16
  • 70
  • 120

1 Answers1

2

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)
Community
  • 1
  • 1
Uli Köhler
  • 13,012
  • 16
  • 70
  • 120
  • 4
    `maybeMaybeToMaybe` is just `Control.Monad.join`. – Michael Snoyman Mar 05 '14 at 06:52
  • @MichaelSnoyman Thank you very much for noting this! I replaced `maybeMaybeToMaybe` by `join` in the code above, which made it a lot simpler! Also, I removed the internal import by using `responseBuilder` – Uli Köhler Mar 05 '14 at 16:03