packages feed

polysemy-http 0.4.0.2 → 0.4.0.3

raw patch · 5 files changed

+187/−190 lines, 5 filesdep −co-log-coredep −co-log-polysemy

Dependencies removed: co-log-core, co-log-polysemy

Files

− Changelog.md
@@ -1,8 +0,0 @@-# 0.3.0.0-* Add support for cookies--# 0.2.0.3-* removed the base-noprelude dependency in favor of using a `hiding` mixin--# 0.1.0.0-* initial release
− README.md
@@ -1,172 +0,0 @@-# About--This Haskell library provides a [Polysemy] effect for running HTTP requests-with [http-client].--# Example--```haskell-import Polysemy (runM, resourceToIO)-import qualified Polysemy.Http as Http-import Polysemy.Http (interpretHttpNative, interpretLogStdout)--main :: IO ()-main = do-  result <- runM $-    resourceToIO $-    interpretLogStdout $-    interpretHttpNative $-    Http.request (Http.get "hackage.haskell.org" "package/polysemy-http")-  print result-```--# API--## Request--The effect constructor `Http.request` takes an argument of type-`Polysemy.Http.Data.Request.Request`:--```haskell-data Request =-  Request {-    _method :: Method,-    _host :: Host,-    _port :: Maybe Port,-    _tls :: Tls,-    _path :: Path,-    _headers :: [(HeaderName, HeaderValue)],-    _cookies :: CookieJar,-    _query :: [(QueryKey, Maybe QueryValue)],-    _body :: Body-  }-```--Most of these fields are just newtypes, except for `Method`, which is an enum:--```haskell-data Method =-  Get | Post | ... | Custom Text-```--It has an `IsString` instance, so you can just write `"GET"` or `"delete"`.--All `Text` newtypes have `IsString` as well, and they will be converted to-`CI` and `ByteString` if needed when they are passed to [http-client].-`Body` is an `LByteString` newtype since that is what [aeson] typically-produces.-The port field is intended for nonstandard ports – if it is `Nothing`, the port-will be determined from `tls`.--## Response--`Http.request` returns `Either HttpError (Response LByteString)`, with-`Polysemy.Http.Data.Response.Response` looking like this:--```haskell-data Response b =-  Response {-    _status :: Status,-    _body :: b,-    _headers :: [Header],-    _cookies :: CookieJar-  }--data Header =-  Header {-    name :: HeaderName,-    value :: HeaderValue-  }-```--`Status` is from `http-types`, because it has some helpful combinators. Its-`Header` is just an alias, so this newtype is provided.-The parameter `b` is intended to allow you to write interpreters that produce-`Text` or something else, for example for [#testing].--# Streaming--The higher-order constructor `Http.stream` opens and closes the request-manually and passes the response to a handler function.-The function `streamResponse` provides a simpler interface for this mechanism-that runs a loop that passes individual chunks produced by [http-client] to-a callback handler of type `∀ x . StreamEvent r c h x -> Sem r x` that should-look like this:--```haskell-handle ::-  StreamEvent Double (IO ByteString) Int a ->-  Sem r a-handle = \case-  StreamEvent.Acquire (Response status body headers) ->-    pure 1-  StreamEvent.Chunk handle (StreamChunk c) ->-    pure ()-  StreamEvent.Result (Response status body headers) handle ->-    pure 5.5-  StreamEvent.Release handle ->-    pure ()--run :: Sem r Double-run =-  Http.streamResponse (Request.get "host.com" "path/to/file") handle-```--If you were e.g. to write the data to disk, you would open the file in the-`Acquire` block, write the `ByteString` `c` in `Chunk`, and close the file in-`Release`.-The parameter `h` could then be `Handle`.-The callbacks are wrapped in `Resource.bracket`, so `Release` is guaranteed to-be called (as much as `Resource` is reliable).-The `Result` block is called when the transfer is complete; its returned value-is finally returned from `streamHandler.`-The `handle` is an arbitrary identifier that the user can return from-`Acquire`; it is not needed for the machinery and may be `()`.--# Entity--The library also provides effects for request and response entity de/encoding,-`EntityDecode d m a` and `EntityEncode d m a`, making it possible to abstract-over json implementations or content types using interpreters.-Since the effects are parameterized by the codec data type, one interpreter per-type must be used.--Implementations for [aeson] are available as `interpretEntityDecodeAeson` and-`interpretEntityEncodeAeson`:--```haskell-import Polysemy (run)-import qualified Polysemy.Http as Http-import Polysemy.Http (interpretEntityDecodeAeson)--data Dat { a :: Maybe Int, b :: Text }-deriving (Show, FromJSON)--main :: IO-main =-  print $ run $ interpretEntityDecodeAeson $ Http.decode "{ \"b\": \"hello\" }"-```--There is not integration with the `Http` effect for this.--# Testing--Polysemy makes it very easy to switch the native interpreter for a mock, and-there is a convenience interpreter named `interpretHttpStrict` that allows you-to specify a list of responses and chunks that should be produced:--```haskell-main :: IO ()-main = do-  result <- runM $-    resourceToIO $-    interpretLogStdout $-    interpretHttpStrict [Response (toEnum 200) "foo" []] [] $-    Http.request (Http.get "hackage.haskell.org" "package/polysemy-http")-  print result-```--[Polysemy]: https://hackage.haskell.org/package/polysemy-[http-client]: https://hackage.haskell.org/package/http-client-[http-types]: https://hackage.haskell.org/package/http-types-[aeson]: https://hackage.haskell.org/package/aeson
+ changelog.md view
@@ -0,0 +1,11 @@+# 0.4.0.0+* Use `CookieJar` in the `Response` instead of requiring users to extract them from the headers.++# 0.3.0.0+* Add support for cookies.++# 0.2.0.3+* Remove the `base-noprelude` dependency in favor of using a `hiding` mixin.++# 0.1.0.0+* Initial release.
polysemy-http.cabal view
@@ -5,9 +5,9 @@ -- see: https://github.com/sol/hpack  name:           polysemy-http-version:        0.4.0.2+version:        0.4.0.3 synopsis:       Polysemy effect for http-client-description:    Please see the README on Github at <https://github.com/tek/polysemy-http>+description:    See <https://hackage.haskell.org/package/polysemy-http/docs/Polysemy-Http.html> category:       Network homepage:       https://github.com/tek/polysemy-http#readme bug-reports:    https://github.com/tek/polysemy-http/issues@@ -18,8 +18,8 @@ license-file:   LICENSE build-type:     Simple extra-source-files:-    README.md-    Changelog.md+    readme.md+    changelog.md  source-repository head   type: git@@ -111,8 +111,6 @@     , base ==4.*     , bytestring     , case-insensitive ==1.2.*-    , co-log-core >=0.2.1 && <0.3-    , co-log-polysemy >=0.0.1.2 && <0.1     , composition >=1.0.2 && <1.1     , containers     , data-default ==0.7.*@@ -204,8 +202,6 @@     , base ==4.*     , bytestring     , case-insensitive ==1.2.*-    , co-log-core >=0.2.1 && <0.3-    , co-log-polysemy >=0.0.1.2 && <0.1     , composition >=1.0.2 && <1.1     , containers     , data-default ==0.7.*@@ -306,8 +302,6 @@     , base ==4.*     , bytestring     , case-insensitive ==1.2.*-    , co-log-core >=0.2.1 && <0.3-    , co-log-polysemy >=0.0.1.2 && <0.1     , composition >=1.0.2 && <1.1     , containers     , data-default ==0.7.*
+ readme.md view
@@ -0,0 +1,172 @@+# About++This Haskell library provides a [Polysemy] effect for running HTTP requests+with [http-client].++# Example++```haskell+import Polysemy (runM, resourceToIO)+import qualified Polysemy.Http as Http+import Polysemy.Http (interpretHttpNative, interpretLogStdout)++main :: IO ()+main = do+  result <- runM $+    resourceToIO $+    interpretLogStdout $+    interpretHttpNative $+    Http.request (Http.get "hackage.haskell.org" "package/polysemy-http")+  print result+```++# API++## Request++The effect constructor `Http.request` takes an argument of type+`Polysemy.Http.Data.Request.Request`:++```haskell+data Request =+  Request {+    _method :: Method,+    _host :: Host,+    _port :: Maybe Port,+    _tls :: Tls,+    _path :: Path,+    _headers :: [(HeaderName, HeaderValue)],+    _cookies :: CookieJar,+    _query :: [(QueryKey, Maybe QueryValue)],+    _body :: Body+  }+```++Most of these fields are just newtypes, except for `Method`, which is an enum:++```haskell+data Method =+  Get | Post | ... | Custom Text+```++It has an `IsString` instance, so you can just write `"GET"` or `"delete"`.++All `Text` newtypes have `IsString` as well, and they will be converted to+`CI` and `ByteString` if needed when they are passed to [http-client].+`Body` is an `LByteString` newtype since that is what [aeson] typically+produces.+The port field is intended for nonstandard ports – if it is `Nothing`, the port+will be determined from `tls`.++## Response++`Http.request` returns `Either HttpError (Response LByteString)`, with+`Polysemy.Http.Data.Response.Response` looking like this:++```haskell+data Response b =+  Response {+    _status :: Status,+    _body :: b,+    _headers :: [Header],+    _cookies :: CookieJar+  }++data Header =+  Header {+    name :: HeaderName,+    value :: HeaderValue+  }+```++`Status` is from `http-types`, because it has some helpful combinators. Its+`Header` is just an alias, so this newtype is provided.+The parameter `b` is intended to allow you to write interpreters that produce+`Text` or something else, for example for [#testing].++# Streaming++The higher-order constructor `Http.stream` opens and closes the request+manually and passes the response to a handler function.+The function `streamResponse` provides a simpler interface for this mechanism+that runs a loop that passes individual chunks produced by [http-client] to+a callback handler of type `∀ x . StreamEvent r c h x -> Sem r x` that should+look like this:++```haskell+handle ::+  StreamEvent Double (IO ByteString) Int a ->+  Sem r a+handle = \case+  StreamEvent.Acquire (Response status body headers) ->+    pure 1+  StreamEvent.Chunk handle (StreamChunk c) ->+    pure ()+  StreamEvent.Result (Response status body headers) handle ->+    pure 5.5+  StreamEvent.Release handle ->+    pure ()++run :: Sem r Double+run =+  Http.streamResponse (Request.get "host.com" "path/to/file") handle+```++If you were e.g. to write the data to disk, you would open the file in the+`Acquire` block, write the `ByteString` `c` in `Chunk`, and close the file in+`Release`.+The parameter `h` could then be `Handle`.+The callbacks are wrapped in `Resource.bracket`, so `Release` is guaranteed to+be called (as much as `Resource` is reliable).+The `Result` block is called when the transfer is complete; its returned value+is finally returned from `streamHandler.`+The `handle` is an arbitrary identifier that the user can return from+`Acquire`; it is not needed for the machinery and may be `()`.++# Entity++The library also provides effects for request and response entity de/encoding,+`EntityDecode d m a` and `EntityEncode d m a`, making it possible to abstract+over json implementations or content types using interpreters.+Since the effects are parameterized by the codec data type, one interpreter per+type must be used.++Implementations for [aeson] are available as `interpretEntityDecodeAeson` and+`interpretEntityEncodeAeson`:++```haskell+import Polysemy (run)+import qualified Polysemy.Http as Http+import Polysemy.Http (interpretEntityDecodeAeson)++data Dat { a :: Maybe Int, b :: Text }+deriving (Show, FromJSON)++main :: IO+main =+  print $ run $ interpretEntityDecodeAeson $ Http.decode "{ \"b\": \"hello\" }"+```++There is not integration with the `Http` effect for this.++# Testing++Polysemy makes it very easy to switch the native interpreter for a mock, and+there is a convenience interpreter named `interpretHttpStrict` that allows you+to specify a list of responses and chunks that should be produced:++```haskell+main :: IO ()+main = do+  result <- runM $+    resourceToIO $+    interpretLogStdout $+    interpretHttpStrict [Response (toEnum 200) "foo" []] [] $+    Http.request (Http.get "hackage.haskell.org" "package/polysemy-http")+  print result+```++[Polysemy]: https://hackage.haskell.org/package/polysemy+[http-client]: https://hackage.haskell.org/package/http-client+[http-types]: https://hackage.haskell.org/package/http-types+[aeson]: https://hackage.haskell.org/package/aeson