packages feed

dormouse-client 0.2.1.0 → 0.3.0.0

raw patch · 8 files changed

+60/−60 lines, 8 filesdep +streamly-coredep ~bytestringdep ~dormouse-uridep ~hedgehogPVP ok

version bump matches the API change (PVP)

Dependencies added: streamly-core

Dependency ranges changed: bytestring, dormouse-uri, hedgehog, hspec-hedgehog, http-api-data, streamly, streamly-bytestring, text, vector

API changes (from Hackage documentation)

- Dormouse.Client: ChunkedTransfer :: SerialT IO Word8 -> RawRequestPayload
+ Dormouse.Client: ChunkedTransfer :: Stream IO Word8 -> RawRequestPayload
- Dormouse.Client: DefinedContentLength :: Word64 -> SerialT IO Word8 -> RawRequestPayload
+ Dormouse.Client: DefinedContentLength :: Word64 -> Stream IO Word8 -> RawRequestPayload
- Dormouse.Client: data AnyUrl
+ Dormouse.Client: data () => AnyUrl
- Dormouse.Client: data Uri
+ Dormouse.Client: data () => Uri
- Dormouse.Client: data Url (scheme :: Symbol)
+ Dormouse.Client: data () => Url (scheme :: Symbol)
- Dormouse.Client: deserialiseRequest :: ResponsePayload body tag => Proxy tag -> HttpResponse (SerialT IO Word8) -> IO (HttpResponse body)
+ Dormouse.Client: deserialiseRequest :: ResponsePayload body tag => Proxy tag -> HttpResponse (Stream IO Word8) -> IO (HttpResponse body)
- Dormouse.Client: newtype UriException
+ Dormouse.Client: newtype () => UriException
- Dormouse.Client: newtype UrlException
+ Dormouse.Client: newtype () => UrlException
- Dormouse.Client: send :: (MonadDormouseClient m, IsUrl url) => HttpRequest url method RawRequestPayload contentTag acceptTag -> (HttpResponse (SerialT IO Word8) -> IO (HttpResponse b)) -> m (HttpResponse b)
+ Dormouse.Client: send :: (MonadDormouseClient m, IsUrl url) => HttpRequest url method RawRequestPayload contentTag acceptTag -> (HttpResponse (Stream IO Word8) -> IO (HttpResponse b)) -> m (HttpResponse b)
- Dormouse.Client.MonadIOImpl: sendHttp :: (HasDormouseClientConfig env, MonadReader env m, MonadIO m, IsUrl url) => HttpRequest url method RawRequestPayload contentTag acceptTag -> (HttpResponse (SerialT IO Word8) -> IO (HttpResponse b)) -> m (HttpResponse b)
+ Dormouse.Client.MonadIOImpl: sendHttp :: (HasDormouseClientConfig env, MonadReader env m, MonadIO m, IsUrl url) => HttpRequest url method RawRequestPayload contentTag acceptTag -> (HttpResponse (Stream IO Word8) -> IO (HttpResponse b)) -> m (HttpResponse b)

Files

dormouse-client.cabal view
@@ -1,13 +1,11 @@ cabal-version: 1.18 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.37.0. -- -- see: https://github.com/sol/hpack------ hash: 0bc74a501091f246473fee31ae5056f9e5c7f721a44e98ffd0a1126dce07304d  name:           dormouse-client-version:        0.2.1.0+version:        0.3.0.0 synopsis:       Simple, type-safe and testable HTTP client description:    An HTTP client designed to be productive, easy to use, easy to test, flexible and safe!                 .@@ -67,20 +65,21 @@       aeson >=2.0 && <3.0     , attoparsec >=0.13.2.4 && <0.15     , base >=4.7 && <5-    , bytestring >=0.10.8 && <0.11.0+    , bytestring >=0.10.8 && <0.12.0     , case-insensitive >=1.2.1.0 && <2.0.0     , containers >=0.6.2.1 && <0.7-    , dormouse-uri-    , http-api-data >=0.4.1.1 && <0.5+    , dormouse-uri ==0.3.*+    , http-api-data >=0.4.1.1 && <0.6     , http-client >=0.6.4.1 && <0.8.0     , http-client-tls >=0.3.5.3 && <0.4     , http-types >=0.12.3 && <0.13     , mtl >=2.2.2 && <3     , safe-exceptions >=0.1.7 && <0.2.0-    , streamly >=0.8.0 && <0.9-    , streamly-bytestring >=0.1.2 && <0.2+    , streamly ==0.10.*+    , streamly-bytestring ==0.2.*+    , streamly-core ==0.2.*     , template-haskell >=2.15.0 && <3.0.0-    , text >=1.2.4 && <2.0.0+    , text >=2.0.0 && <3.0.0   default-language: Haskell2010  test-suite dormouse-client-test@@ -120,24 +119,25 @@       aeson >=2.0 && <3.0     , attoparsec >=0.13.2.4 && <0.15     , base >=4.7 && <5-    , bytestring >=0.10.8 && <0.11.0+    , bytestring >=0.10.8 && <0.12.0     , case-insensitive >=1.2.1.0 && <2.0.0     , containers >=0.6.2.1 && <0.7     , dormouse-uri-    , hedgehog >=1.0.1 && <2+    , hedgehog     , hspec >=2.0.0 && <3     , hspec-discover >=2.0.0 && <3-    , hspec-hedgehog >=0.0.1.2 && <0.1-    , http-api-data >=0.4.1.1 && <0.5+    , hspec-hedgehog+    , http-api-data >=0.4.1.1 && <0.6     , http-client >=0.6.4.1 && <0.8.0     , http-client-tls >=0.3.5.3 && <0.4     , http-types >=0.12.3 && <0.13     , mtl >=2.2.2 && <3     , safe-exceptions >=0.1.7 && <0.2.0     , scientific >=0.3.6.2 && <0.4-    , streamly >=0.8.0 && <0.9-    , streamly-bytestring >=0.1.2 && <0.2+    , streamly ==0.10.*+    , streamly-bytestring ==0.2.*+    , streamly-core ==0.2.*     , template-haskell >=2.15.0 && <3.0.0-    , text >=1.2.4 && <2.0.0-    , vector >=0.12.0.3 && <0.13+    , text >=2.0.0 && <3.0.0+    , vector   default-language: Haskell2010
src/Dormouse/Client/Class.hs view
@@ -9,7 +9,7 @@ import Dormouse.Client.Types ( HttpRequest(..), HttpResponse(..) ) import Dormouse.Url ( IsUrl ) import Network.HTTP.Client ( Manager )-import Streamly ( SerialT )+import qualified Streamly.Data.Stream as Stream  -- | The configuration options required to run Dormouse newtype DormouseClientConfig = DormouseClientConfig { clientManager :: Manager }@@ -24,4 +24,4 @@ -- | MonadDormouseClient describes the capability to send HTTP requests and receive an HTTP response class Monad m => MonadDormouseClient m where   -- | Sends a supplied HTTP request and retrieves a response within the supplied monad @m@-  send :: IsUrl url => HttpRequest url method RawRequestPayload contentTag acceptTag -> (HttpResponse (SerialT IO Word8) -> IO (HttpResponse b)) -> m (HttpResponse b)+  send :: IsUrl url => HttpRequest url method RawRequestPayload contentTag acceptTag -> (HttpResponse (Stream.Stream IO Word8) -> IO (HttpResponse b)) -> m (HttpResponse b)
src/Dormouse/Client/MonadIOImpl.hs view
@@ -26,18 +26,16 @@ import qualified Network.HTTP.Client as C import qualified Network.HTTP.Types as T import qualified Network.HTTP.Types.Status as NC-import Streamly-import qualified Streamly.Prelude as S import qualified Streamly.External.ByteString as SEB-import qualified Streamly.Internal.Data.Array.Stream.Foreign as SIMA+import qualified Streamly.Data.Stream as Stream -givesPopper :: SerialT IO Word8 -> C.GivesPopper ()+givesPopper :: Stream.Stream IO Word8 -> C.GivesPopper () givesPopper rawStream k = do-  let initialStream = SIMA.arraysOf 32768 rawStream+  let initialStream = Stream.chunksOf 32768 rawStream   streamState <- newIORef initialStream   let popper = do         stream <- readIORef streamState-        test <- S.uncons stream+        test <- Stream.uncons stream         case test of           Just (elems, stream') -> writeIORef streamState stream' $> SEB.fromArray elems           Nothing               -> return B.empty@@ -68,13 +66,13 @@     , C.queryString = encodeQuery queryText     } -responseStream :: C.Response C.BodyReader -> SerialT IO Word8+responseStream :: C.Response C.BodyReader -> Stream.Stream IO Word8 responseStream resp = -    S.repeatM (C.brRead $ C.responseBody resp)-  & S.takeWhile (not . B.null)-  & S.concatMap (S.unfold SEB.read)+    Stream.repeatM (C.brRead $ C.responseBody resp)+  & Stream.takeWhile (not . B.null)+  & Stream.concatMap (Stream.unfold SEB.reader) -sendHttp :: (HasDormouseClientConfig env, MonadReader env m, MonadIO m, IsUrl url) => HttpRequest url method RawRequestPayload contentTag acceptTag -> (HttpResponse (SerialT IO Word8) -> IO (HttpResponse b)) -> m (HttpResponse b)+sendHttp :: (HasDormouseClientConfig env, MonadReader env m, MonadIO m, IsUrl url) => HttpRequest url method RawRequestPayload contentTag acceptTag -> (HttpResponse (Stream.Stream IO Word8) -> IO (HttpResponse b)) -> m (HttpResponse b) sendHttp HttpRequest { requestMethod = method, requestUrl = url, requestBody = reqBody, requestHeaders = reqHeaders} deserialiseResp = do   manager <- clientManager <$> reader getDormouseClientConfig   let initialRequest = genClientRequestFromUrlComponents $ asAnyUrl url
src/Dormouse/Client/Payload.hs view
@@ -32,10 +32,10 @@ import qualified Data.ByteString.Lazy as LB import qualified Data.Map.Strict as Map import qualified Web.FormUrlEncoded as W-import Streamly-import qualified Streamly.Prelude as S+import qualified Streamly.Data.Fold as Fold import qualified Streamly.External.ByteString as SEB import qualified Streamly.External.ByteString.Lazy as SEBL+import qualified Streamly.Data.Stream as Stream  -- | Describes an association between a type @tag@ and a specific Media Type class HasMediaType tag where@@ -44,9 +44,9 @@ -- | A raw HTTP Request payload consisting of a stream of bytes with either a defined Content Length or using Chunked Transfer Encoding data RawRequestPayload   -- | DefinedContentLength represents a payload where the size of the message is known in advance and the content length header can be computed-  = DefinedContentLength Word64 (SerialT IO Word8)+  = DefinedContentLength Word64 (Stream.Stream IO Word8)   -- | ChunkedTransfer represents a payload with indertiminate length, to be sent using chunked transfer encoding-  | ChunkedTransfer (SerialT IO Word8)+  | ChunkedTransfer (Stream.Stream IO Word8)  -- | RequestPayload relates a type of content and a payload tag used to describe that type to its byte stream representation and the constraints required to encode it class HasMediaType contentTag => RequestPayload body contentTag where@@ -56,7 +56,7 @@ -- | ResponsePayload relates a type of content and a payload tag used to describe that type  to its byte stream representation and the constraints required to decode it class HasMediaType tag => ResponsePayload body tag where   -- | Decodes the high level representation from the supplied byte stream-  deserialiseRequest :: Proxy tag -> HttpResponse (SerialT IO Word8) -> IO (HttpResponse body)+  deserialiseRequest :: Proxy tag -> HttpResponse (Stream.Stream IO Word8) -> IO (HttpResponse body)  data JsonPayload = JsonPayload @@ -67,12 +67,12 @@   serialiseRequest _ r =      let b = requestBody r         lbs = encode b-    in r { requestBody = DefinedContentLength (fromIntegral . LB.length $ lbs) (S.unfold SEBL.read lbs) }+    in r { requestBody = DefinedContentLength (fromIntegral . LB.length $ lbs) (Stream.unfold SEBL.reader lbs) }  instance (FromJSON body) => ResponsePayload body JsonPayload where   deserialiseRequest _ resp = do     let stream = responseBody resp-    bs <- S.fold SEB.write stream+    bs <- Stream.fold SEB.write stream     body <- either (throw . DecodingException . T.pack) return . eitherDecodeStrict $ bs     return $ resp { responseBody = body } @@ -89,12 +89,12 @@   serialiseRequest _ r =     let b = requestBody r         lbs = W.urlEncodeAsForm b-    in r { requestBody = DefinedContentLength (fromIntegral . LB.length $ lbs) (S.unfold SEBL.read lbs) }+    in r { requestBody = DefinedContentLength (fromIntegral . LB.length $ lbs) (Stream.unfold SEBL.reader lbs) }  instance (W.FromForm body) => ResponsePayload body UrlFormPayload where   deserialiseRequest _ resp = do     let stream = responseBody resp-    bs <- S.fold SEB.write $ stream+    bs <- Stream.fold SEB.write $ stream     body <- either (throw . DecodingException) return . W.urlDecodeAsForm $ LB.fromStrict bs     return $ resp { responseBody = body } @@ -108,25 +108,25 @@   mediaType _ = Nothing  instance RequestPayload Empty EmptyPayload where-  serialiseRequest _ r = r { requestBody = DefinedContentLength 0 S.nil }+  serialiseRequest _ r = r { requestBody = DefinedContentLength 0 Stream.nil }  instance ResponsePayload Empty EmptyPayload where   deserialiseRequest _ resp = do     let stream = responseBody resp-    body <- Empty <$ S.drain stream+    body <- Empty <$ Stream.fold Fold.drain stream     return $ resp { responseBody = body }  -- | A type tag used to indicate that a request\/response has no payload noPayload :: Proxy EmptyPayload noPayload = Proxy :: Proxy EmptyPayload -decodeTextContent :: (MonadThrow m, MonadIO m) => HttpResponse (SerialT m Word8) -> m (HttpResponse T.Text)+decodeTextContent :: (MonadThrow m, MonadIO m) => HttpResponse (Stream.Stream m Word8) -> m (HttpResponse T.Text) decodeTextContent resp = do   let contentTypeHV = getHeaderValue "Content-Type" resp   mediaType' <- traverse MTH.parseMediaType contentTypeHV   let maybeCharset = mediaType' >>= Map.lookup "charset" . MTH.parameters   let stream = responseBody resp-  bs <- S.fold SEB.write $ stream+  bs <- Stream.fold SEB.write $ stream   return $ resp { responseBody = decodeContent maybeCharset bs }     where       decodeContent maybeCharset bs' = @@ -144,7 +144,7 @@   serialiseRequest _ r =     let b = requestBody r         lbs = LB.fromStrict $ TE.encodeUtf8 b -    in r { requestBody = DefinedContentLength (fromIntegral . LB.length $ lbs) (S.unfold SEBL.read lbs) }+    in r { requestBody = DefinedContentLength (fromIntegral . LB.length $ lbs) (Stream.unfold SEBL.reader lbs) }  instance ResponsePayload T.Text HtmlPayload where   deserialiseRequest _ resp = decodeTextContent resp
src/Dormouse/Client/Test/Class.hs view
@@ -26,10 +26,9 @@ import Dormouse.Client.Payload ( RawRequestPayload(..) ) import Dormouse.Client.Types ( HttpRequest(..), HttpResponse(..) ) import Dormouse.Url ( IsUrl )-import Streamly ( SerialT )-import qualified Streamly.Prelude as S import qualified Streamly.External.ByteString as SEB import qualified Streamly.External.ByteString.Lazy as SEBL+import qualified Streamly.Data.Stream as Stream  -- | MonadDormouseTestClient describes the capability to send and receive specifically ByteString typed HTTP Requests and Responses class Monad m => MonadDormouseTestClient m where@@ -47,13 +46,13 @@  instance (Monad m, MonadIO m, MonadDormouseTestClient m) => MonadDormouseClient m where   send req deserialiseResp = do-    reqBody <- liftIO . S.fold SEB.write . extricateRequestStream . requestBody $ req+    reqBody <- liftIO . Stream.fold SEB.write . extricateRequestStream . requestBody $ req     let reqBs = req {requestBody = reqBody}     respBs <- expectBs reqBs-    let respStream = S.unfold SEBL.read . LB.fromStrict $ responseBody respBs+    let respStream = Stream.unfold SEBL.reader . LB.fromStrict $ responseBody respBs     liftIO $ deserialiseResp $ respBs { responseBody = respStream }     where -      extricateRequestStream :: RawRequestPayload -> SerialT IO Word8+      extricateRequestStream :: RawRequestPayload -> Stream.Stream IO Word8       extricateRequestStream (DefinedContentLength _ s) = s       extricateRequestStream (ChunkedTransfer s) = s 
test/Dormouse/Client/Generators/Json.hs view
@@ -10,6 +10,7 @@ import qualified Data.Aeson.Key as AK import qualified Data.Scientific as S import qualified Data.Vector as V+import qualified Data.Char as C import Hedgehog import qualified Hedgehog.Gen as Gen @@ -23,8 +24,11 @@ genJsonNull = pure A.Null  genJsonString :: Range Int -> Gen A.Value-genJsonString sr = fmap A.String $ Gen.text sr Gen.unicode+genJsonString sr = fmap A.String $ Gen.text sr jsonChar +jsonChar :: Gen Char+jsonChar = Gen.filter (\c -> c /= '\"' && c /= '\\' && (not $ C.isControl c) && c /= '\r' && c /= '\n') Gen.unicode+ genJsonBool :: Gen A.Value genJsonBool = fmap A.Bool Gen.bool @@ -43,7 +47,7 @@ genJsonObject ranges = fmap A.object $ Gen.list ar genNameValue   where     genNameValue = do-      name <- Gen.text sr Gen.unicode+      name <- Gen.text sr jsonChar       value <- genJsonValue ranges       return (AK.fromText name, value)     sr = stringRanges ranges
test/Dormouse/Client/PayloadSpec.hs view
@@ -9,15 +9,13 @@ import Dormouse.Client.Generators.Text import Dormouse.Client.Payload -import Streamly-import qualified Streamly.Prelude as S- import Data.Proxy  import Test.Hspec import Test.Hspec.Hedgehog import qualified Hedgehog.Range as Range import qualified Streamly.External.ByteString as SEB+import qualified Streamly.Data.Stream as Stream  spec :: Spec spec = before setup $ do@@ -29,7 +27,7 @@           resp = HttpResponse              { responseStatusCode = 200             , responseHeaders = Map.fromList [("Content-Type", "text/plain; charset=iso-8859-1")]-            , responseBody = S.unfold SEB.read txt+            , responseBody = Stream.unfold SEB.read txt             }           expectedLatin1Text = decodeLatin1 txt         resp' <- liftIO . deserialiseRequest html $ resp@@ -41,7 +39,7 @@           resp = HttpResponse              { responseStatusCode = 200             , responseHeaders = Map.fromList [("Content-Type", "text/plain; charset=utf8")]-            , responseBody = S.unfold SEB.read txt+            , responseBody = Stream.unfold SEB.read txt             }           expectedUtf8Text = decodeUtf8 txt         resp' <- liftIO . deserialiseRequest html $ resp@@ -53,7 +51,7 @@           resp = HttpResponse              { responseStatusCode = 200             , responseHeaders = Map.empty-            , responseBody = S.unfold SEB.read txt+            , responseBody = Stream.unfold SEB.read txt             }           expectedUtf8Text = decodeUtf8 txt         resp' <- liftIO . deserialiseRequest html $ resp
test/Dormouse/ClientSpec.hs view
@@ -10,10 +10,10 @@   ) where  import Control.Concurrent.MVar-import Control.Exception.Safe (MonadThrow)+import Control.Exception.Safe (MonadThrow, catch, Exception, SomeException (SomeException)) import Control.Monad.IO.Class import Control.Monad.Reader-import Data.Aeson (encode, Value)+import Data.Aeson (encode, Value, ToJSON (toJSON)) import qualified Data.Map.Strict as Map import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as LB@@ -21,6 +21,7 @@ import Dormouse.Client.Test.Class import Dormouse.Url.QQ import Dormouse.Client.Generators.Json+ import Test.Hspec import Test.Hspec.Hedgehog