Copyright | © 2016 Mark Karpov, Michael Snoyman |
---|---|
License | BSD 3 clause |
Maintainer | Mark Karpov <markkarpov@openmailbox.org> |
Stability | experimental |
Portability | portable |
Safe Haskell | None |
Language | Haskell2010 |
The module extends functionality available in Network.HTTP.Req with Conduit helpers for streaming big request bodies.
The package re-uses some pieces of code from the http-conduit
package,
but not to the extent that depending on that package is reasonable.
- data ReqBodySource = ReqBodySource Int64 (Source IO ByteString)
- req' :: (MonadHttp m, HttpMethod method, HttpBody body, HttpBodyAllowed (AllowsBody method) (ProvidesBody body)) => method -> Url scheme -> body -> (Request -> Manager -> m a) -> Option scheme -> m a
- httpSource :: MonadResource m => Request -> Manager -> Producer m ByteString
Streaming request bodies
data ReqBodySource Source #
This body option streams contents of request body from given
Source
. The Int64
value is size of the data in bytes.
Using of this body option does not set the Content-Type
header.
ReqBodySource Int64 (Source IO ByteString) |
HttpBody ReqBodySource Source # | |
Streaming response bodies
Streaming response is a bit tricky as acquiring and releasing a resource
(initiating a connection and then closing it in our case) in context of
conduit
streaming requires working with
ResourceT
monad transformer. This does not
play well with the framework req
builds.
Essentially there are only two ways to make it work:
- Require that every
MonadHttp
must be an instance ofMonadResource
. This obviously makes thereq
package harder to work with and less user-friendly. Not to mention that most of the time the instance won't be necessary. - Use the
withReqManager
in combination withReturnRequest
response interpretation to get bothManager
andRequest
and then delegate the work to to a custom callback.
We go with the second option. Here is an example of how to stream 100000 bytes and save them to a file:
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} module Main (main) where import Control.Exception (throwIO) import Control.Monad.IO.Class (MonadIO (..)) import Control.Monad.Trans.Resource (ResourceT) import Data.Conduit ((=$=), runConduitRes, ConduitM) import Network.HTTP.Req import Network.HTTP.Req.Conduit import qualified Data.Conduit.Binary as CB instance MonadHttp (ConduitM i o (ResourceT IO)) where handleHttpException = liftIO . throwIO main :: IO () main = runConduitRes $ do let size = 100000 :: Int req' GET (https "httpbin.org" /: "bytes" /~ size) NoReqBody httpSource mempty =$= CB.sinkFile "my-favorite-file.bin"
:: (MonadHttp m, HttpMethod method, HttpBody body, HttpBodyAllowed (AllowsBody method) (ProvidesBody body)) | |
=> method | HTTP method |
-> Url scheme |
|
-> body | Body of the request |
-> (Request -> Manager -> m a) | How to perform actual request |
-> Option scheme | Collection of optional parameters |
-> m a | Result |
Mostly like req
with respect to its arguments, but instead of a hint
how to interpret response it takes a callback that allows to perform a
request using arbitrary code.
:: MonadResource m | |
=> Request | Pre-formed |
-> Manager | Manger to use |
-> Producer m ByteString | Response body as a |
Perform an HTTP request and get the response as a Producer
.