Search code examples
haskellnetwork-programminghttp-conduit

Building a query string for a get request


Suppose I have this function performing a get request:

import Network.HTTP.Conduit
import qualified Data.ByteString.Char8 as C8

get :: String -> [(C8.ByteString, C8.ByteString)] -> IO (Response LC8.ByteString)
get url par = do
  request <- parseUrl url 
  res <- withManager $ httpLbs $ createReq request
  return res
  where
    createReq req = 
      req {
            method = methodGet
          , queryString = map (\(k, v) -> k ++ "&=" ++ v) par -- ????
          }

I believe there must a simpler way to create a query string. My method both is not simple and wrong as it doesn't care about "?" and "&" (there must be "?" in the beggining and must not be "&" at the end). So how do I create a query string for a get request from [(C8.ByteString, C8.ByteString)] ? Moreover, (++) can't be used with ByteString. But I haven't found any example which is surprising.


Solution

  • Use functions from Network.HTTP.Types.URI present in http-types package. Infact, http-types is one of the dependency package for http-conduit.

    λ> import Network.HTTP.Types.URI
    λ> import Data.ByteString
    λ> :set -XOverloadedStrings
    λ> let getData = [("key1", Just "value1"), ("key2", Just "value2")] :: [(ByteString, Maybe ByteString)]
    λ> renderQuery True getData
    "?key1=value1&key2=value2"
    λ> renderQuery False getData
    "key1=value1&key2=value2"
    

    See how the Bool value in renderQuery controls prepending ? to the request.

    Update: Starting from http-client 0.3.6, Michael Snoyman has added this functionality in setQueryString as indicated by him in the comments.