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