I am using Haskell to send a POST HTTP request via the http-client
package, but as a response i am getting an error from the remote server. I would like to inspect my request in order to be sure that i am sending the expected parameters in the body.
I managed to bind my request to a variable in the Haskell interpreter, but i can't figure out how to see its body. When i use requestBody
on my request i get a value of type RequestBody, but it is not an instance of show.
In the library i can't find any helpful function. There are just many constructors, and some functions related to a Popper
type.
How can i inspect that value? This seems a common use case to me, yet the library doesn't seem to support it. Am i using it wrong?
I know what Wireshark is and how to use it, but i expect to be able to programmatically inspect what i am sending
RequestBody
has five constructors.
data RequestBody
= RequestBodyLBS L.ByteString
| RequestBodyBS S.ByteString
| RequestBodyBuilder Int64 Builder
| RequestBodyStream Int64 (GivesPopper ())
| RequestBodyStreamChunked (GivesPopper ())
First two are wrappers of bytestring, the third is a Blaze.ByteString.Builder
which can be easily converted to bytestring, the last two are functions of type (IO ByteString -> IO a) -> IO a
as the type synonym showed:
type Popper = IO S.ByteString
type NeedsPopper a = Popper -> IO a
type GivesPopper a = NeedsPopper a -> IO a
feed them >>= print
multiple times and you will get the complete request body printed to console.
You should not do this because these GivesPopper ()
generators can only be executed once: if you extract the content beforehand then the request body will not be sent to the server. That's why they didn't provide a Show instance for RequestBody
data type. You'd better capture the buckets containing your http request with e.g. Wireshark.
I have a data structure in my code and i don't see why i shouldn't be able to inspect it. You mention that inspecting the request might somehow consume it. This is weird in a language like Haskell where immutability and explicit side effects are the rule
That's right for most of the types in Haskell, but Popper
is actually IO S.ByteString
, a bytestring stream (usually) populated by a file handler, while handler in Haskell is an MVar
which is not so different from variables in imperative languages: it may be a value or null, may be assigned and reassigned and the side effect is visible globally.
An example from Network.HTTP.Client.MultipartFormData
:
streamFile :: FilePath -> GivesPopper ()
streamFile fp np =
withFile fp ReadMode $ np . go
where
-- go :: Handle -> Popper
go h = BS.hGetSome h defaultChunkSize
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