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 +0/−8
- README.md +0/−172
- changelog.md +11/−0
- polysemy-http.cabal +4/−10
- readme.md +172/−0
− 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