I'm trying to learn how to send simple string via HTTP/POST using Haskell and http-conduit
(so that it works with https as well), reading the target url from a file, but it still seems all a bit overwhelming to me.
Basically the equivalent of what I learned to do with Racket here: Sending HTTP POST in Racket
Could someone give me a small or most basic example of doing this?
I tried reading https://stackoverflow.com/a/13465653/5083453
Sure! The weird Haskell thing here to note is Haskell's record system. When you call parseUrl
with a URL string, http-conduit
is giving you back a Request
record with some default values filled out, but the library expects you to fill out the rest.
For example, parseUrl
always returns a Request
with the HTTP method set to GET. It's up to us to overwrite that value by using the record update syntax – the thing where you append curly braces with new keys and values.
{-# LANGUAGE OverloadedStrings #-}
module Lib where
import Data.Aeson
import Network.HTTP.Client
buildRequest :: String -> RequestBody -> IO Request
buildRequest url body = do
nakedRequest <- parseRequest url
return (nakedRequest { method = "POST", requestBody = body })
send :: RequestBody -> IO ()
send s = do
manager <- newManager defaultManagerSettings
request <- buildRequest "http://httpbin.org/post" s
response <- httpLbs request manager
let Just obj = decode (responseBody response)
print (obj :: Object)
If you run this in GHCi, you should be able to send POSTs to httpbin:
λ> :set -XOverloadedStrings
λ> send "hello there"
fromList [("origin",String "<snip>")
,("args",Object (fromList []))
,("json",Null)
,("data",String "hello there")
,("url",String "http://httpbin.org/post")
,("headers",Object (fromList [("Accept-Encoding",String "gzip")
,("Host",String "httpbin.org")
,("Content-Length",String "11")]))
,("files",Object (fromList []))
,("form",Object (fromList []))]
You'll also need the OverloadedStrings extension. Without it, two things will happen:
nakedRequest { method = "POST" }
won't typecheck because the library expects a (strict) ByteString
from the bytestring
library. By default, "POST"
and all string literals have type String
a.k.a [Char]
. While there is a function called pack
that takes String
and returns ByteString
, it's much simpler to turn on overloaded strings. The compiler automatically calls pack
on your behalf. There's more to it than that; see Oliver's blog post for the nitty gritty details.
Another expression that won't typecheck is send "hello there"
. send
expects a RequestBody
. And while again there's a function somewhere that would have type String -> RequestBody
, it's much easier to turn on overloaded strings and have the compiler call it for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With