@@ -1,19 +1,9 @@
1−{-# LANGUAGE BangPatterns #-}
3{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
4−{-# LANGUAGE DeriveDataTypeable #-}
5−{-# LANGUAGE DeriveGeneric #-}
6−{-# LANGUAGE DeriveLift #-}
7−{-# LANGUAGE FlexibleInstances #-}
8−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
9−{-# LANGUAGE KindSignatures #-}
10{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE LambdaCase #-}
11−{-# LANGUAGE MultiParamTypeClasses #-}
12{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE OverloadedStrings #-}
13{-# LANGUAGE QuasiQuotes #-}
4{-# LANGUAGE QuasiQuotes #-}
14−{-# LANGUAGE RankNTypes #-}
15{-# LANGUAGE RecordWildCards #-}
5{-# LANGUAGE RecordWildCards #-}
16−{-# LANGUAGE ScopedTypeVariables #-}
6+{-# LANGUAGE RoleAnnotations #-}
17{-# LANGUAGE TemplateHaskellQuotes #-}
7{-# LANGUAGE TemplateHaskellQuotes #-}
18{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE TypeFamilies #-}
19{-# LANGUAGE UndecidableInstances #-}
9{-# LANGUAGE UndecidableInstances #-}
@@ -29,61 +19,40 @@
30-- The documentation below is structured in such a way that the most
20-- The documentation below is structured in such a way that the most
31-- important information is presented first: you learn how to do HTTP
21-- important information is presented first: you learn how to do HTTP
32−-- requests, how to embed them in any monad you have, and then it gives you
22+-- requests, how to embed them in the monad you have, and then it gives you
33-- details about less-common things you may want to know about. The
23-- details about less-common things you may want to know about. The
34-- documentation is written with sufficient coverage of details and
24-- documentation is written with sufficient coverage of details and
35-- examples, and it's designed to be a complete tutorial on its own.
25-- examples, and it's designed to be a complete tutorial on its own.
37−-- /(A modest intro goes here, click on 'req' to start making requests.)/
39-- === About the library
27-- === About the library
41−-- Req is an easy-to-use, type-safe, expandable, high-level HTTP client
29+-- Req is an HTTP client library that attempts to be easy-to-use, type-safe,
42−-- library that just works without any fooling around.
30+-- and expandable.
44−-- What does the phrase “easy-to-use” mean? It means that the library is
32+-- “Easy-to-use” means that the library is designed to be beginner-friendly
45−-- designed to be beginner-friendly so it's simple to add to your monad
33+-- so it's simple to add to your monad stack, intuitive to work with,
46−-- stack, intuitive to work with, well-documented, and does not get in your
34+-- well-documented, and does not get in your way. Doing HTTP requests is a
47−-- way. Doing HTTP requests is a common task and Haskell library for this
35+-- common task and a Haskell library for this should be approachable and
48−-- should be very approachable and clear to beginners, thus certain
49−-- compromises were made. For example, one cannot currently modify
36+-- clear to beginners, thus certain compromises were made. For example, one
50−-- 'L.ManagerSettings' of the default manager because the library always
37+-- cannot currently modify 'L.ManagerSettings' of the default manager
51−-- uses the same implicit global manager for simplicity and maximal
38+-- because the library always uses the same implicit global manager for
52−-- connection sharing. There is a way to use your own manager with different
39+-- simplicity and maximal connection sharing. There is a way to use your own
53−-- settings, but it requires a bit more typing.
40+-- manager with different settings, but it requires more typing.
55−-- “Type-safe” means that the library is protective and eliminates certain
42+-- “Type-safe” means that the library tries to eliminate certain classes of
56−-- classes of errors. For example, we have correct-by-construction 'Url's,
43+-- errors. For example, we have correct-by-construction URLs; it is
57−-- it's guaranteed that the user does not send the request body when using
44+-- guaranteed that the user does not send the request body when using
58−-- methods like 'GET' or 'OPTIONS', and the amount of implicit assumptions
45+-- methods like GET or OPTIONS, and the amount of implicit assumptions is
59−-- is minimized by making the user specify his\/her intentions in an
46+-- minimized by making the user specify their intentions in an explicit
60−-- explicit form (for example, it's not possible to avoid specifying the
47+-- form. For example, it's not possible to avoid specifying the body or the
61−-- body or method of request). Authentication methods that assume HTTPS
48+-- method of a request. Authentication methods that assume HTTPS force the
62−-- force the user to use HTTPS at the type level. The library also carefully
49+-- user to use HTTPS at the type level.
63−-- hides underlying types from the lower-level @http-client@ package because
64−-- those types are not safe enough (for example 'L.Request' is an instance
65−-- of 'Data.String.IsString' and, if it's malformed, it will blow up at
68−-- “Expandable” refers to the ability of the library to be expanded without
51+-- “Expandable” refers to the ability to create new components without
69−-- having to resort to ugly hacking. For example, it's possible to define
52+-- having to resort to hacking. For example, it's possible to define your
70−-- your own HTTP methods, create new ways to construct the body of a
53+-- own HTTP methods, create new ways to construct the body of a request,
71−-- request, create new authorization options, perform a request in a
54+-- create new authorization options, perform a request in a different way,
72−-- different way, and create your own methods to parse and represent a
55+-- and create your own methods to parse a response.
73−-- response. As the user extends the library to satisfy his\/her special
74−-- needs, the new solutions will work just like the built-ins. However, all
75−-- of the common cases are also covered by the library out-of-the-box.
77−-- “High-level” means that there are less details to worry about. The
78−-- library is a result of my experiences as a Haskell consultant. Working
79−-- for several clients, who had very different projects, showed me that the
80−-- library should adapt easily to any particular style of writing Haskell
81−-- applications. For example, some people prefer throwing exceptions, while
82−-- others are concerned with purity. Just define 'handleHttpException'
83−-- accordingly when making your monad instance of 'MonadHttp' and it will
84−-- play together seamlessly. Finally, the library cuts down boilerplate
85−-- considerably, and helps you write concise, easy to read, and maintainable
88-- === Using with other libraries
57-- === Using with other libraries
@@ -112,6 +81,7 @@ module Network.HTTP.Req
112 -- $making-a-request
81 -- $making-a-request
116 withReqManager,
86 withReqManager,
@@ -149,6 +119,7 @@ module Network.HTTP.Req
149 useHttpsURI,
119 useHttpsURI,
153 -- ** Body
124 -- ** Body
@@ -173,11 +144,13 @@ module Network.HTTP.Req
173 -- $query-parameters
144 -- $query-parameters
175 queryFlag,
146 queryFlag,
176 QueryParam (..),
148 QueryParam (..),
178 -- *** Headers
150 -- *** Headers
180 attachHeader,
152 attachHeader,
182 -- *** Cookies
155 -- *** Cookies
183 -- $cookies
156 -- $cookies
@@ -224,56 +197,78 @@ module Network.HTTP.Req
225 -- * Other
198 -- * Other
226 HttpException (..),
199 HttpException (..),
200+ isStatusCodeException,
227 CanHaveBody (..),
201 CanHaveBody (..),
228 Scheme (..),
202 Scheme (..),
232−import qualified Blaze.ByteString.Builder as BB
206+import Blaze.ByteString.Builder qualified as BB
233import Control.Applicative
207import Control.Applicative
234import Control.Arrow (first, second)
208import Control.Arrow (first, second)
235−import Control.Exception hiding (TypeError)
209+import Control.Exception hiding (Handler (..), TypeError)
210+import Control.Monad (guard, void, (>=>))
236import Control.Monad.Base
211import Control.Monad.Base
212+import Control.Monad.Catch (Handler (..), MonadCatch, MonadMask, MonadThrow)
237import Control.Monad.IO.Class
213import Control.Monad.IO.Class
238−import Control.Monad.Reader
214+import Control.Monad.IO.Unlift
215+import Control.Monad.Reader (ReaderT (ReaderT), ask, lift, runReaderT)
216+import Control.Monad.Trans.Accum (AccumT)
217+import Control.Monad.Trans.Cont (ContT)
239import Control.Monad.Trans.Control
218import Control.Monad.Trans.Control
219+import Control.Monad.Trans.Except (ExceptT)
220+import Control.Monad.Trans.Identity (IdentityT)
221+import Control.Monad.Trans.Maybe (MaybeT)
222+import Control.Monad.Trans.RWS.CPS qualified as RWS.CPS
223+import Control.Monad.Trans.RWS.Lazy qualified as RWS.Lazy
224+import Control.Monad.Trans.RWS.Strict qualified as RWS.Strict
225+import Control.Monad.Trans.Select (SelectT)
226+import Control.Monad.Trans.State.Lazy qualified as State.Lazy
227+import Control.Monad.Trans.State.Strict qualified as State.Strict
228+import Control.Monad.Trans.Writer.CPS qualified as Writer.CPS
229+import Control.Monad.Trans.Writer.Lazy qualified as Writer.Lazy
230+import Control.Monad.Trans.Writer.Strict qualified as Writer.Strict
240import Control.Retry
231import Control.Retry
241import Data.Aeson (FromJSON (..), ToJSON (..))
232import Data.Aeson (FromJSON (..), ToJSON (..))
242−import qualified Data.Aeson as A
233+import Data.Aeson qualified as A
243import Data.ByteString (ByteString)
234import Data.ByteString (ByteString)
244−import qualified Data.ByteString as B
235+import Data.ByteString qualified as B
245−import qualified Data.ByteString.Lazy as BL
236+import Data.ByteString.Lazy qualified as BL
246−import qualified Data.CaseInsensitive as CI
237+import Data.CaseInsensitive qualified as CI
247import Data.Data (Data)
238import Data.Data (Data)
239+import Data.Default.Class (def)
248import Data.Function (on)
240import Data.Function (on)
249import Data.IORef
241import Data.IORef
250import Data.Kind (Constraint, Type)
242import Data.Kind (Constraint, Type)
251import Data.List (foldl', nubBy)
243import Data.List (foldl', nubBy)
252import Data.List.NonEmpty (NonEmpty (..))
244import Data.List.NonEmpty (NonEmpty (..))
253−import qualified Data.List.NonEmpty as NE
245+import Data.List.NonEmpty qualified as NE
254import Data.Maybe (fromMaybe)
246import Data.Maybe (fromMaybe)
255import Data.Proxy
247import Data.Proxy
256−import Data.Semigroup hiding (Option, option)
248+import Data.Semigroup (Endo (..))
249+import Data.Set qualified as S
257import Data.Text (Text)
250import Data.Text (Text)
258−import qualified Data.Text as T
251+import Data.Text qualified as T
259−import qualified Data.Text.Encoding as T
252+import Data.Text.Encoding qualified as T
260import Data.Typeable (Typeable, cast)
253import Data.Typeable (Typeable, cast)
261import GHC.Generics
254import GHC.Generics
262import GHC.TypeLits
255import GHC.TypeLits
263−import qualified Language.Haskell.TH as TH
256+import Language.Haskell.TH qualified as TH
264−import qualified Language.Haskell.TH.Quote as TH
257+import Language.Haskell.TH.Quote qualified as TH
265−import qualified Language.Haskell.TH.Syntax as TH
258+import Language.Haskell.TH.Syntax qualified as TH
266−import qualified Network.Connection as NC
259+import Network.Connection qualified as NC
267−import qualified Network.HTTP.Client as L
260+import Network.HTTP.Client qualified as L
268−import qualified Network.HTTP.Client.Internal as LI
261+import Network.HTTP.Client.Internal qualified as LI
269−import qualified Network.HTTP.Client.MultipartFormData as LM
262+import Network.HTTP.Client.MultipartFormData qualified as LM
270−import qualified Network.HTTP.Client.TLS as L
263+import Network.HTTP.Client.TLS qualified as L
271−import qualified Network.HTTP.Types as Y
264+import Network.HTTP.Types qualified as Y
272import System.IO.Unsafe (unsafePerformIO)
265import System.IO.Unsafe (unsafePerformIO)
273import Text.URI (URI)
266import Text.URI (URI)
274−import qualified Text.URI as URI
267+import Text.URI qualified as URI
275−import qualified Text.URI.QQ as QQ
268+import Text.URI.QQ qualified as QQ
276−import qualified Web.Authenticate.OAuth as OAuth
269+import Web.Authenticate.OAuth qualified as OAuth
270+import Web.FormUrlEncoded (FromForm (..), ToForm (..))
271+import Web.FormUrlEncoded qualified as Form
277import Web.HttpApiData (ToHttpApiData (..))
272import Web.HttpApiData (ToHttpApiData (..))
279----------------------------------------------------------------------------
274----------------------------------------------------------------------------
@@ -298,7 +293,7 @@ import Web.HttpApiData (ToHttpApiData (..))
299-- @body@ is a body option such as 'NoReqBody' or 'ReqBodyJson'. The
294-- @body@ is a body option such as 'NoReqBody' or 'ReqBodyJson'. The
300-- tutorial has a section about HTTP bodies, but usage is very
295-- tutorial has a section about HTTP bodies, but usage is very
301−-- straightforward and should be clear from the examples below.
296+-- straightforward and should be clear from the examples.
303-- @response@ is a type hint how to make and interpret response of an HTTP
298-- @response@ is a type hint how to make and interpret response of an HTTP
304-- request. Out-of-the-box it can be the following:
299-- request. Out-of-the-box it can be the following:
@@ -426,12 +421,7 @@ req ::
426 -- | Response
421 -- | Response
427 m response
422 m response
428req method url body responseProxy options =
423req method url body responseProxy options =
429− reqBr method url body (options <> extraOptions) getHttpResponse
424+ reqCb method url body responseProxy options pure
432− case acceptHeader responseProxy of
434− Just accept -> header "Accept" accept
436-- | A version of 'req' that does not use one of the predefined instances of
426-- | A version of 'req' that does not use one of the predefined instances of
437-- 'HttpResponse' but instead allows the user to consume @'L.Response'
427-- 'HttpResponse' but instead allows the user to consume @'L.Response'
@@ -456,7 +446,58 @@ reqBr ::
456 (L.Response L.BodyReader -> IO a) ->
446 (L.Response L.BodyReader -> IO a) ->
457 -- | Result
447 -- | Result
459−reqBr method url body options consume = req' method url body options $ \request manager -> do
449+reqBr method url body options consume =
450+ req' method url body options (reqHandler consume)
452+-- | A version of 'req' that takes a callback to modify the 'L.Request', but
453+-- otherwise performs the request identically.
460+ HttpResponse response,
461+ HttpBodyAllowed (AllowsBody method) (ProvidesBody body)
465+ -- | 'Url'—location of resource
467+ -- | Body of the request
469+ -- | A hint how to interpret response
471+ -- | Collection of optional parameters
473+ -- | Callback to modify the request
474+ (L.Request -> m L.Request) ->
477+reqCb method url body responseProxy options adjustRequest =
478+ req' method url body (options <> extraOptions) $ \request manager -> do
479+ request' <- adjustRequest request
480+ reqHandler getHttpResponse request' manager
483+ case acceptHeader responseProxy of
485+ Just accept -> header "Accept" accept
487+-- | The default handler function that the higher-level request functions
488+-- pass to 'req''. Internal function.
493+ -- | How to get final result from a 'L.Response'
494+ (L.Response L.BodyReader -> IO b) ->
495+ -- | 'L.Request' to perform
497+ -- | 'L.Manager' to use
500+reqHandler consume request manager = do
460 HttpConfig {..} <- getHttpConfig
501 HttpConfig {..} <- getHttpConfig
461 let wrapVanilla = handle (throwIO . VanillaHttpException)
502 let wrapVanilla = handle (throwIO . VanillaHttpException)
462 wrapExc = handle (throwIO . LI.toHttpException request)
503 wrapExc = handle (throwIO . LI.toHttpException request)
@@ -472,12 +513,23 @@ reqBr method url body options consume = req' method url body options $ \request
472 r' <- L.responseOpen request manager
513 r' <- L.responseOpen request manager
473 writeIORef rref (Just r')
514 writeIORef rref (Just r')
474 return r'
515 return r'
516+ exceptionRetryPolicies =
518+ ++ [ \retryStatus -> Handler $ \e ->
519+ return $ httpConfigRetryJudgeException retryStatus e
477 httpConfigRetryPolicy
523 httpConfigRetryPolicy
478− (\st r -> return $ httpConfigRetryJudge st r)
524+ (\retryStatus r -> return $ httpConfigRetryJudge retryStatus r)
527+ httpConfigRetryPolicy
528+ exceptionRetryPolicies
479− (const openResponse)
529+ (const openResponse)
480− (preview, r') <- grabPreview bodyPreviewLength r
532+ (preview, r') <- grabPreview httpConfigBodyPreviewLength r
481 mapM_ LI.throwHttp (httpConfigCheckResponse request r' preview)
533 mapM_ LI.throwHttp (httpConfigCheckResponse request r' preview)
482 consume r'
534 consume r'
@@ -526,22 +578,22 @@ req' method url body options m = do
526 nubHeaders
578 nubHeaders
527 <> getRequestMod options
579 <> getRequestMod options
528 <> getRequestMod config
580 <> getRequestMod config
529− <> getRequestMod (Womb body :: Womb "body" body)
581+ <> getRequestMod (Tagged body :: Tagged "body" body)
530 <> getRequestMod url
582 <> getRequestMod url
531− <> getRequestMod (Womb method :: Womb "method" method)
583+ <> getRequestMod (Tagged method :: Tagged "method" method)
532 request <- finalizeRequest options request'
584 request <- finalizeRequest options request'
533 withReqManager (m request)
585 withReqManager (m request)
535-- | Perform an action using the global implicit 'L.Manager' that the rest
587-- | Perform an action using the global implicit 'L.Manager' that the rest
536−-- of the library uses. This allows to reuse connections that the
588+-- of the library uses. This allows us to reuse connections that the
537-- 'L.Manager' controls.
589-- 'L.Manager' controls.
538−withReqManager :: MonadIO m => (L.Manager -> m a) -> m a
590+withReqManager :: (MonadIO m) => (L.Manager -> m a) -> m a
539−withReqManager m = liftIO (readIORef globalManager) >>= m
591+withReqManager m = m globalManager
541−-- | Global 'L.Manager' that 'req' uses. Here we just go with the default
593+-- | The global 'L.Manager' that 'req' uses. Here we just go with the
542−-- settings, so users don't need to deal with this manager stuff at all, but
594+-- default settings, so users don't need to deal with this manager stuff at
543−-- when we create a request, instance 'HttpConfig' can affect the default
595+-- all, but when we create a request, instance 'HttpConfig' can affect the
544−-- settings via 'getHttpConfig'.
596+-- default settings via 'getHttpConfig'.
546-- A note about safety, in case 'unsafePerformIO' looks suspicious to you.
598-- A note about safety, in case 'unsafePerformIO' looks suspicious to you.
547-- The value of 'globalManager' is named and lives on top level. This means
599-- The value of 'globalManager' is named and lives on top level. This means
@@ -549,16 +601,16 @@ withReqManager m = liftIO (readIORef globalManager) >>= m
549-- manager. From that moment on the 'IORef' will be just reused—exactly the
601-- manager. From that moment on the 'IORef' will be just reused—exactly the
550-- behavior we want here in order to maximize connection sharing. GHC could
602-- behavior we want here in order to maximize connection sharing. GHC could
551-- spoil the plan by inlining the definition, hence the @NOINLINE@ pragma.
603-- spoil the plan by inlining the definition, hence the @NOINLINE@ pragma.
552−globalManager :: IORef L.Manager
604+globalManager :: L.Manager
553globalManager = unsafePerformIO $ do
605globalManager = unsafePerformIO $ do
554 context <- NC.initConnectionContext
606 context <- NC.initConnectionContext
555 let settings =
607 let settings =
556 L.mkManagerSettingsContext
608 L.mkManagerSettingsContext
557 (Just context)
609 (Just context)
558− (NC.TLSSettingsSimple False False False)
610+ def
560 manager <- L.newManager settings
612 manager <- L.newManager settings
561− newIORef manager
613+ return manager
562{-# NOINLINE globalManager #-}
614{-# NOINLINE globalManager #-}
564----------------------------------------------------------------------------
616----------------------------------------------------------------------------
@@ -572,13 +624,13 @@ globalManager = unsafePerformIO $ do
572-- When writing a library, keep your API polymorphic in terms of
624-- When writing a library, keep your API polymorphic in terms of
573-- 'MonadHttp', only define instance of 'MonadHttp' in final application.
625-- 'MonadHttp', only define instance of 'MonadHttp' in final application.
574-- Another option is to use a @newtype@-wrapped monad stack and define
626-- Another option is to use a @newtype@-wrapped monad stack and define
575−-- 'MonadHttp' for it. As of version /0.4.0/, the 'Req' monad that follows
627+-- 'MonadHttp' for it. As of the version /0.4.0/, the 'Req' monad that
576−-- this strategy is provided out-of-the-box (see below).
628+-- follows this strategy is provided out-of-the-box (see below).
578-- | A type class for monads that support performing HTTP requests.
630-- | A type class for monads that support performing HTTP requests.
579-- Typically, you only need to define the 'handleHttpException' method
631-- Typically, you only need to define the 'handleHttpException' method
580-- unless you want to tweak 'HttpConfig'.
632-- unless you want to tweak 'HttpConfig'.
581−class MonadIO m => MonadHttp m where
633+class (MonadIO m) => MonadHttp m where
582 -- | This method describes how to deal with 'HttpException' that was
634 -- | This method describes how to deal with 'HttpException' that was
583 -- caught by the library. One option is to re-throw it if you are OK with
635 -- caught by the library. One option is to re-throw it if you are OK with
584 -- exceptions, but if you prefer working with something like
636 -- exceptions, but if you prefer working with something like
@@ -586,17 +638,16 @@ class MonadIO m => MonadHttp m where
586 -- 'Control.Monad.Except.throwError'.
638 -- 'Control.Monad.Except.throwError'.
587 handleHttpException :: HttpException -> m a
639 handleHttpException :: HttpException -> m a
589− -- | Return 'HttpConfig' to be used when performing HTTP requests. Default
641+ -- | Return the 'HttpConfig' to be used when performing HTTP requests.
590− -- implementation returns its 'def' value, which is described in the
642+ -- Default implementation returns its 'def' value, which is described in
591− -- documentation for the type. Common usage pattern with manually defined
643+ -- the documentation for the type. Common usage pattern with manually
592− -- 'getHttpConfig' is to return some hard-coded value, or a value
644+ -- defined 'getHttpConfig' is to return some hard-coded value, or a value
593 -- extracted from 'Control.Monad.Reader.MonadReader' if a more flexible
645 -- extracted from 'Control.Monad.Reader.MonadReader' if a more flexible
594 -- approach to configuration is desirable.
646 -- approach to configuration is desirable.
595 getHttpConfig :: m HttpConfig
647 getHttpConfig :: m HttpConfig
596 getHttpConfig = return defaultHttpConfig
648 getHttpConfig = return defaultHttpConfig
598−-- | 'HttpConfig' contains general and default settings to be used when
650+-- | 'HttpConfig' contains settings to be used when making HTTP requests.
599−-- making HTTP requests.
600data HttpConfig = HttpConfig
651data HttpConfig = HttpConfig
601 { -- | Proxy to use. By default values of @HTTP_PROXY@ and @HTTPS_PROXY@
652 { -- | Proxy to use. By default values of @HTTP_PROXY@ and @HTTPS_PROXY@
602 -- environment variables are respected, this setting overwrites them.
653 -- environment variables are respected, this setting overwrites them.
@@ -640,8 +691,8 @@ data HttpConfig = HttpConfig
640 -- | The retry policy to use for request retrying. By default 'def' is
691 -- | The retry policy to use for request retrying. By default 'def' is
641 -- used (see 'RetryPolicyM').
692 -- used (see 'RetryPolicyM').
643− -- __Note__: signature of this function was changed in the version
694+ -- __Note__: signature of this function was changed to disallow 'IO' in
644− -- /1.0.0/.
695+ -- version /1.0.0/ and then changed back to its current form in /3.1.0/.
646 -- @since 0.3.0
697 -- @since 0.3.0
647 httpConfigRetryPolicy :: RetryPolicyM IO,
698 httpConfigRetryPolicy :: RetryPolicyM IO,
@@ -652,11 +703,21 @@ data HttpConfig = HttpConfig
652 -- /1.0.0/.
703 -- /1.0.0/.
654 -- @since 0.3.0
705 -- @since 0.3.0
655− httpConfigRetryJudge :: forall b. RetryStatus -> L.Response b -> Bool
706+ httpConfigRetryJudge :: forall b. RetryStatus -> L.Response b -> Bool,
707+ -- | Similar to 'httpConfigRetryJudge', but is used to decide when to
708+ -- retry requests that resulted in an exception. By default it retries
709+ -- on response timeout and connection timeout (changed in version
713+ httpConfigRetryJudgeException :: RetryStatus -> SomeException -> Bool,
714+ -- | Max length of preview fragment of response body.
717+ httpConfigBodyPreviewLength :: forall a. (Num a) => a
659−-- | Default value of 'HttpConfig'.
720+-- | The default value of 'HttpConfig'.
661-- @since 2.0.0
722-- @since 2.0.0
662defaultHttpConfig :: HttpConfig
723defaultHttpConfig :: HttpConfig
@@ -678,7 +739,16 @@ defaultHttpConfig =
678 524, -- A timeout occurred
739 524, -- A timeout occurred
679 598, -- (Informal convention) Network read timeout error
740 598, -- (Informal convention) Network read timeout error
680 599 -- (Informal convention) Network connect timeout error
741 599 -- (Informal convention) Network connect timeout error
743+ httpConfigRetryJudgeException = \_ e ->
744+ case fromException e of
745+ Just (L.HttpExceptionRequest _ c) ->
747+ L.ResponseTimeout -> True
748+ L.ConnectionTimeout -> True
751+ httpConfigBodyPreviewLength = 1024
684 statusCode = Y.statusCode . L.responseStatus
754 statusCode = Y.statusCode . L.responseStatus
@@ -691,7 +761,7 @@ instance RequestComponent HttpConfig where
691 LI.requestManagerOverride = httpConfigAltManager
761 LI.requestManagerOverride = httpConfigAltManager
694−-- | A monad that allows to run 'req' in any 'IO'-enabled monad without
764+-- | A monad that allows us to run 'req' in any 'IO'-enabled monad without
695-- having to define new instances.
765-- having to define new instances.
697-- @since 0.4.0
767-- @since 0.4.0
@@ -700,9 +770,19 @@ newtype Req a = Req (ReaderT HttpConfig IO a)
700 ( Functor,
770 ( Functor,
701 Applicative,
771 Applicative,
703− MonadIO
773+ MonadIO,
778+deriving instance MonadThrow Req
781+deriving instance MonadCatch Req
784+deriving instance MonadMask Req
706instance MonadBase IO Req where
786instance MonadBase IO Req where
707 liftBase = liftIO
787 liftBase = liftIO
@@ -717,12 +797,87 @@ instance MonadHttp Req where
717 handleHttpException = Req . lift . throwIO
797 handleHttpException = Req . lift . throwIO
718 getHttpConfig = Req ask
798 getHttpConfig = Req ask
801+instance (MonadHttp m, Monoid w) => MonadHttp (AccumT w m) where
802+ handleHttpException = lift . handleHttpException
803+ getHttpConfig = lift getHttpConfig
806+instance (MonadHttp m) => MonadHttp (ContT r m) where
807+ handleHttpException = lift . handleHttpException
808+ getHttpConfig = lift getHttpConfig
811+instance (MonadHttp m) => MonadHttp (ExceptT e m) where
812+ handleHttpException = lift . handleHttpException
813+ getHttpConfig = lift getHttpConfig
816+instance (MonadHttp m) => MonadHttp (IdentityT m) where
817+ handleHttpException = lift . handleHttpException
818+ getHttpConfig = lift getHttpConfig
821+instance (MonadHttp m) => MonadHttp (MaybeT m) where
822+ handleHttpException = lift . handleHttpException
823+ getHttpConfig = lift getHttpConfig
826+instance (MonadHttp m) => MonadHttp (ReaderT r m) where
827+ handleHttpException = lift . handleHttpException
828+ getHttpConfig = lift getHttpConfig
831+instance (MonadHttp m, Monoid w) => MonadHttp (RWS.CPS.RWST r w s m) where
832+ handleHttpException = lift . handleHttpException
833+ getHttpConfig = lift getHttpConfig
836+instance (MonadHttp m, Monoid w) => MonadHttp (RWS.Lazy.RWST r w s m) where
837+ handleHttpException = lift . handleHttpException
838+ getHttpConfig = lift getHttpConfig
841+instance (MonadHttp m, Monoid w) => MonadHttp (RWS.Strict.RWST r w s m) where
842+ handleHttpException = lift . handleHttpException
843+ getHttpConfig = lift getHttpConfig
846+instance (MonadHttp m) => MonadHttp (SelectT r m) where
847+ handleHttpException = lift . handleHttpException
848+ getHttpConfig = lift getHttpConfig
851+instance (MonadHttp m) => MonadHttp (State.Lazy.StateT s m) where
852+ handleHttpException = lift . handleHttpException
853+ getHttpConfig = lift getHttpConfig
856+instance (MonadHttp m) => MonadHttp (State.Strict.StateT s m) where
857+ handleHttpException = lift . handleHttpException
858+ getHttpConfig = lift getHttpConfig
861+instance (MonadHttp m, Monoid w) => MonadHttp (Writer.CPS.WriterT w m) where
862+ handleHttpException = lift . handleHttpException
863+ getHttpConfig = lift getHttpConfig
866+instance (MonadHttp m, Monoid w) => MonadHttp (Writer.Lazy.WriterT w m) where
867+ handleHttpException = lift . handleHttpException
868+ getHttpConfig = lift getHttpConfig
871+instance (MonadHttp m, Monoid w) => MonadHttp (Writer.Strict.WriterT w m) where
872+ handleHttpException = lift . handleHttpException
873+ getHttpConfig = lift getHttpConfig
720-- | Run a computation in the 'Req' monad with the given 'HttpConfig'. In
875-- | Run a computation in the 'Req' monad with the given 'HttpConfig'. In
721−-- case of exceptional situation an 'HttpException' will be thrown.
876+-- the case of an exceptional situation an 'HttpException' will be thrown.
723-- @since 0.4.0
878-- @since 0.4.0
725− MonadIO m =>
880+ (MonadIO m) =>
726 -- | 'HttpConfig' to use
881 -- | 'HttpConfig' to use
727 HttpConfig ->
882 HttpConfig ->
728 -- | Computation to run
883 -- | Computation to run
@@ -770,14 +925,15 @@ instance HttpMethod PUT where
770 type AllowsBody PUT = 'CanHaveBody
925 type AllowsBody PUT = 'CanHaveBody
771 httpMethodName Proxy = Y.methodPut
926 httpMethodName Proxy = Y.methodPut
773−-- | 'DELETE' method. This data type does not allow having request body with
928+-- | 'DELETE' method. RFC 7231 allows a payload in DELETE but without
774−-- 'DELETE' requests, as it should be. However some APIs may expect 'DELETE'
929+-- semantics.
775−-- requests to have bodies, in that case define your own variation of
930+--
776−-- 'DELETE' method and allow it to have a body.
931+-- __Note__: before version /3.4.0/ this method did not allow request
777data DELETE = DELETE
933data DELETE = DELETE
779instance HttpMethod DELETE where
935instance HttpMethod DELETE where
780− type AllowsBody DELETE = 'NoBody
936+ type AllowsBody DELETE = 'CanHaveBody
781 httpMethodName Proxy = Y.methodDelete
937 httpMethodName Proxy = Y.methodDelete
783-- | 'TRACE' method.
939-- | 'TRACE' method.
@@ -826,7 +982,7 @@ class HttpMethod a where
826 -- | Return name of the method as a 'ByteString'.
982 -- | Return name of the method as a 'ByteString'.
827 httpMethodName :: Proxy a -> ByteString
983 httpMethodName :: Proxy a -> ByteString
829−instance HttpMethod method => RequestComponent (Womb "method" method) where
985+instance (HttpMethod method) => RequestComponent (Tagged "method" method) where
830 getRequestMod _ = Endo $ \x ->
986 getRequestMod _ = Endo $ \x ->
831 x {L.method = httpMethodName (Proxy :: Proxy method)}
987 x {L.method = httpMethodName (Proxy :: Proxy method)}
@@ -868,21 +1024,20 @@ instance HttpMethod method => RequestComponent (Womb "method" method) where
868-- > -- https://%D1%8E%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4.%D1%80%D1%84
1024-- > -- https://%D1%8E%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4.%D1%80%D1%84
869data Url (scheme :: Scheme) = Url Scheme (NonEmpty Text)
1025data Url (scheme :: Scheme) = Url Scheme (NonEmpty Text)
870 -- NOTE The second value is the path segments in reversed order.
1026 -- NOTE The second value is the path segments in reversed order.
871− deriving (Eq, Ord, Show, Data, Typeable, Generic)
1027+ deriving (Eq, Ord, Show, Data, Generic)
1029+type role Url nominal
873-- With template-haskell >=2.15 and text >=1.2.4 Lift can be derived, however
1031-- With template-haskell >=2.15 and text >=1.2.4 Lift can be derived, however
874−-- the derived lift forgets the type of scheme.
1032+-- the derived lift forgets the type of the scheme.
875−instance Typeable scheme => TH.Lift (Url scheme) where
1033+instance (Typeable scheme) => TH.Lift (Url scheme) where
876 lift url =
1034 lift url =
877 TH.dataToExpQ (fmap liftText . cast) url `TH.sigE` case url of
1035 TH.dataToExpQ (fmap liftText . cast) url `TH.sigE` case url of
878 Url Http _ -> [t|Url 'Http|]
1036 Url Http _ -> [t|Url 'Http|]
879 Url Https _ -> [t|Url 'Https|]
1037 Url Https _ -> [t|Url 'Https|]
881 liftText t = TH.AppE (TH.VarE 'T.pack) <$> TH.lift (T.unpack t)
1039 liftText t = TH.AppE (TH.VarE 'T.pack) <$> TH.lift (T.unpack t)
883−#if MIN_VERSION_template_haskell(2,16,0)
884− liftTyped url = TH.TExp <$> TH.lift url
1040+ liftTyped = TH.Code . TH.unsafeTExpCoerce . TH.lift
887-- | Given host name, produce a 'Url' which has “http” as its scheme and
1042-- | Given host name, produce a 'Url' which has “http” as its scheme and
888-- empty path. This also sets port to @80@.
1043-- empty path. This also sets port to @80@.
@@ -894,20 +1049,33 @@ http = Url Http . pure
894https :: Text -> Url 'Https
1049https :: Text -> Url 'Https
895https = Url Https . pure
1050https = Url Https . pure
897−-- | Grow given 'Url' appending a single path segment to it. Note that the
1052+-- | Grow a given 'Url' appending a single path segment to it. Note that the
898-- path segment can be of any type that is an instance of 'ToHttpApiData'.
1053-- path segment can be of any type that is an instance of 'ToHttpApiData'.
899infixl 5 /~
1054infixl 5 /~
901−(/~) :: ToHttpApiData a => Url scheme -> a -> Url scheme
1056+(/~) :: (ToHttpApiData a) => Url scheme -> a -> Url scheme
902Url secure path /~ segment = Url secure (NE.cons (toUrlPiece segment) path)
1057Url secure path /~ segment = Url secure (NE.cons (toUrlPiece segment) path)
904−-- | Type-constrained version of @('/~')@ to remove ambiguity in the cases
1059+-- | A type-constrained version of @('/~')@ to remove ambiguity in the cases
905-- when next URL piece is a 'Data.Text.Text' literal.
1060-- when next URL piece is a 'Data.Text.Text' literal.
906infixl 5 /:
1061infixl 5 /:
908(/:) :: Url scheme -> Text -> Url scheme
1063(/:) :: Url scheme -> Text -> Url scheme
909(/:) = (/~)
1064(/:) = (/~)
1066+-- | Render a 'Url' as 'Text'.
1069+renderUrl :: Url scheme -> Text
1072+ "https://" <> renderParts parts
1074+ "http://" <> renderParts parts
1076+ renderParts parts =
1077+ T.intercalate "/" (reverse $ NE.toList parts)
911-- | The 'useHttpURI' function provides an alternative method to get 'Url'
1079-- | The 'useHttpURI' function provides an alternative method to get 'Url'
912-- (possibly with some 'Option's) from a 'URI'. This is useful when you are
1080-- (possibly with some 'Option's) from a 'URI'. This is useful when you are
913-- given a URL to query dynamically and don't know it beforehand.
1081-- given a URL to query dynamically and don't know it beforehand.
@@ -921,8 +1089,7 @@ useHttpURI uri = do
921 urlHead <- http <$> uriHost uri
1089 urlHead <- http <$> uriHost uri
922 let url = case URI.uriPath uri of
1090 let url = case URI.uriPath uri of
923 Nothing -> urlHead
1091 Nothing -> urlHead
924− Just (_, xs) ->
1092+ Just uriPath -> uriPathToUrl uriPath urlHead
925− foldl' (/:) urlHead (URI.unRText <$> NE.toList xs)
926 return (url, uriOptions uri)
1093 return (url, uriOptions uri)
928-- | Just like 'useHttpURI', but expects the “https” scheme.
1095-- | Just like 'useHttpURI', but expects the “https” scheme.
@@ -934,10 +1101,21 @@ useHttpsURI uri = do
934 urlHead <- https <$> uriHost uri
1101 urlHead <- https <$> uriHost uri
935 let url = case URI.uriPath uri of
1102 let url = case URI.uriPath uri of
936 Nothing -> urlHead
1103 Nothing -> urlHead
937− Just (_, xs) ->
1104+ Just uriPath -> uriPathToUrl uriPath urlHead
938− foldl' (/:) urlHead (URI.unRText <$> NE.toList xs)
939 return (url, uriOptions uri)
1105 return (url, uriOptions uri)
1107+-- | Convert URI path to a 'Url'. Internal.
1111+ (Bool, NonEmpty (URI.RText 'URI.PathPiece)) ->
1114+uriPathToUrl (trailingSlash, xs) urlHead =
1115+ if trailingSlash then path /: T.empty else path
1117+ path = foldl' (/:) urlHead (URI.unRText <$> NE.toList xs)
941-- | A combination of 'useHttpURI' and 'useHttpsURI' for cases when scheme
1119-- | A combination of 'useHttpURI' and 'useHttpsURI' for cases when scheme
942-- is not known in advance.
1120-- is not known in advance.
@@ -1054,21 +1232,21 @@ data NoReqBody = NoReqBody
1054instance HttpBody NoReqBody where
1232instance HttpBody NoReqBody where
1055 getRequestBody NoReqBody = L.RequestBodyBS B.empty
1233 getRequestBody NoReqBody = L.RequestBodyBS B.empty
1057−-- | This body option allows to use a JSON object as request body—probably
1235+-- | This body option allows us to use a JSON object as the request
1058−-- the most popular format right now. Just wrap a data type that is an
1236+-- body—probably the most popular format right now. Just wrap a data type
1059−-- instance of 'ToJSON' type class and you are done: it will be converted to
1237+-- that is an instance of 'ToJSON' type class and you are done: it will be
1060−-- JSON and inserted as request body.
1238+-- converted to JSON and inserted as request body.
1062-- This body option sets the @Content-Type@ header to @\"application/json;
1240-- This body option sets the @Content-Type@ header to @\"application/json;
1063-- charset=utf-8\"@ value.
1241-- charset=utf-8\"@ value.
1064newtype ReqBodyJson a = ReqBodyJson a
1242newtype ReqBodyJson a = ReqBodyJson a
1066−instance ToJSON a => HttpBody (ReqBodyJson a) where
1244+instance (ToJSON a) => HttpBody (ReqBodyJson a) where
1067 getRequestBody (ReqBodyJson a) = L.RequestBodyLBS (A.encode a)
1245 getRequestBody (ReqBodyJson a) = L.RequestBodyLBS (A.encode a)
1068 getRequestContentType _ = pure "application/json; charset=utf-8"
1246 getRequestContentType _ = pure "application/json; charset=utf-8"
1070-- | This body option streams request body from a file. It is expected that
1248-- | This body option streams request body from a file. It is expected that
1071−-- the file size does not change during the streaming.
1249+-- the file size does not change during streaming.
1073-- Using of this body option does not set the @Content-Type@ header.
1251-- Using of this body option does not set the @Content-Type@ header.
1074newtype ReqBodyFile = ReqBodyFile FilePath
1252newtype ReqBodyFile = ReqBodyFile FilePath
@@ -1093,12 +1271,11 @@ newtype ReqBodyLbs = ReqBodyLbs BL.ByteString
1093instance HttpBody ReqBodyLbs where
1271instance HttpBody ReqBodyLbs where
1094 getRequestBody (ReqBodyLbs bs) = L.RequestBodyLBS bs
1272 getRequestBody (ReqBodyLbs bs) = L.RequestBodyLBS bs
1096−-- | Form URL-encoded body. This can hold a collection of parameters which
1274+-- | URL-encoded body. This can hold a collection of parameters which are
1097−-- are encoded similarly to query parameters at the end of query string,
1275+-- encoded similarly to query parameters at the end of query string, with
1098−-- with the only difference that they are stored in request body. The
1276+-- the only difference that they are stored in request body. The similarity
1099−-- similarity is reflected in the API as well, as you can use the same
1277+-- is reflected in the API as well, as you can use the same combinators you
1100−-- combinators you would use to add query parameters: @('=:')@ and
1278+-- would use to add query parameters: @('=:')@ and 'queryFlag'.
1103-- This body option sets the @Content-Type@ header to
1280-- This body option sets the @Content-Type@ header to
1104-- @\"application/x-www-form-urlencoded\"@ value.
1281-- @\"application/x-www-form-urlencoded\"@ value.
@@ -1117,6 +1294,13 @@ newtype FormUrlEncodedParam = FormUrlEncodedParam [(Text, Maybe Text)]
1117instance QueryParam FormUrlEncodedParam where
1294instance QueryParam FormUrlEncodedParam where
1118 queryParam name mvalue =
1295 queryParam name mvalue =
1119 FormUrlEncodedParam [(name, toQueryParam <$> mvalue)]
1296 FormUrlEncodedParam [(name, toQueryParam <$> mvalue)]
1297+ queryParamToList (FormUrlEncodedParam p) = p
1299+-- | Use 'formToQuery'.
1302+instance FromForm FormUrlEncodedParam where
1303+ fromForm = Right . formToQuery
1121-- | Multipart form data. Please consult the
1305-- | Multipart form data. Please consult the
1122-- "Network.HTTP.Client.MultipartFormData" module for how to construct
1306-- "Network.HTTP.Client.MultipartFormData" module for how to construct
@@ -1156,7 +1340,7 @@ instance HttpBody ReqBodyMultipart where
1156-- | Create 'ReqBodyMultipart' request body from a collection of 'LM.Part's.
1340-- | Create 'ReqBodyMultipart' request body from a collection of 'LM.Part's.
1158-- @since 0.2.0
1342-- @since 0.2.0
1159−reqBodyMultipart :: MonadIO m => [LM.Part] -> m ReqBodyMultipart
1343+reqBodyMultipart :: (MonadIO m) => [LM.Part] -> m ReqBodyMultipart
1160reqBodyMultipart parts = liftIO $ do
1344reqBodyMultipart parts = liftIO $ do
1161 boundary <- LM.webkitBoundary
1345 boundary <- LM.webkitBoundary
1162 body <- LM.renderParts boundary parts
1346 body <- LM.renderParts boundary parts
@@ -1184,9 +1368,6 @@ type family ProvidesBody body :: CanHaveBody where
1184-- | This type function allows any HTTP body if method says it
1368-- | This type function allows any HTTP body if method says it
1185-- 'CanHaveBody'. When the method says it should have 'NoBody', the only
1369-- 'CanHaveBody'. When the method says it should have 'NoBody', the only
1186-- body option to use is 'NoReqBody'.
1370-- body option to use is 'NoReqBody'.
1188−-- __Note__: users of GHC 8.0.1 and later will see a slightly more friendly
1189−-- error message when method does not allow a body and body is provided.
1190type family
1371type family
1191 HttpBodyAllowed
1372 HttpBodyAllowed
1192 (allowsBody :: CanHaveBody)
1373 (allowsBody :: CanHaveBody)
@@ -1199,8 +1380,8 @@ type family
1199 TypeError
1380 TypeError
1200 ('Text "This HTTP method does not allow attaching a request body.")
1381 ('Text "This HTTP method does not allow attaching a request body.")
1202−instance HttpBody body => RequestComponent (Womb "body" body) where
1383+instance (HttpBody body) => RequestComponent (Tagged "body" body) where
1203− getRequestMod (Womb body) = Endo $ \x ->
1384+ getRequestMod (Tagged body) = Endo $ \x ->
1205 { L.requestBody = getRequestBody body,
1386 { L.requestBody = getRequestBody body,
1206 L.requestHeaders =
1387 L.requestHeaders =
@@ -1229,8 +1410,8 @@ data Option (scheme :: Scheme)
1229 = Option (Endo (Y.QueryText, L.Request)) (Maybe (L.Request -> IO L.Request))
1410 = Option (Endo (Y.QueryText, L.Request)) (Maybe (L.Request -> IO L.Request))
1231-- NOTE 'QueryText' is just [(Text, Maybe Text)], we keep it along with
1412-- NOTE 'QueryText' is just [(Text, Maybe Text)], we keep it along with
1232−-- Request to avoid appending to existing query string in request every
1413+-- Request to avoid appending to an existing query string in request every
1233−-- time new parameter is added. Additional Maybe (L.Request -> IO
1414+-- time new parameter is added. The additional Maybe (L.Request -> IO
1234-- L.Request) is a finalizer that will be applied after all other
1415-- L.Request) is a finalizer that will be applied after all other
1235-- transformations. This is for authentication methods that sign requests
1416-- transformations. This is for authentication methods that sign requests
1236-- based on data in Request.
1417-- based on data in Request.
@@ -1245,6 +1426,12 @@ instance Monoid (Option scheme) where
1245 mempty = Option mempty Nothing
1426 mempty = Option mempty Nothing
1246 mappend = (<>)
1427 mappend = (<>)
1429+-- | Use 'formToQuery'.
1432+instance FromForm (Option scheme) where
1433+ fromForm = Right . formToQuery
1248-- | A helper to create an 'Option' that modifies only collection of query
1435-- | A helper to create an 'Option' that modifies only collection of query
1249-- parameters. This helper is not a part of the public API.
1436-- parameters. This helper is not a part of the public API.
1250withQueryParams :: (Y.QueryText -> Y.QueryText) -> Option scheme
1437withQueryParams :: (Y.QueryText -> Y.QueryText) -> Option scheme
@@ -1263,7 +1450,7 @@ instance RequestComponent (Option scheme) where
1264-- | Finalize given 'L.Request' by applying a finalizer from the given
1451-- | Finalize given 'L.Request' by applying a finalizer from the given
1265-- 'Option' (if it has any).
1452-- 'Option' (if it has any).
1266−finalizeRequest :: MonadIO m => Option scheme -> L.Request -> m L.Request
1453+finalizeRequest :: (MonadIO m) => Option scheme -> L.Request -> m L.Request
1267finalizeRequest (Option _ mfinalizer) = liftIO . fromMaybe pure mfinalizer
1454finalizeRequest (Option _ mfinalizer) = liftIO . fromMaybe pure mfinalizer
1269----------------------------------------------------------------------------
1456----------------------------------------------------------------------------
@@ -1287,7 +1474,7 @@ infix 7 =:
1287(=:) :: (QueryParam param, ToHttpApiData a) => Text -> a -> param
1474(=:) :: (QueryParam param, ToHttpApiData a) => Text -> a -> param
1288name =: value = queryParam name (pure value)
1475name =: value = queryParam name (pure value)
1290−-- | Construct a flag, that is, valueless query parameter. For example, in
1477+-- | Construct a flag, that is, a valueless query parameter. For example, in
1291-- the following URL @\"a\"@ is a flag, while @\"b\"@ is a query parameter
1478-- the following URL @\"a\"@ is a flag, while @\"b\"@ is a query parameter
1292-- with a value:
1479-- with a value:
@@ -1296,9 +1483,27 @@ name =: value = queryParam name (pure value)
1296-- This operator is defined in terms of 'queryParam':
1483-- This operator is defined in terms of 'queryParam':
1298-- > queryFlag name = queryParam name (Nothing :: Maybe ())
1485-- > queryFlag name = queryParam name (Nothing :: Maybe ())
1299−queryFlag :: QueryParam param => Text -> param
1486+queryFlag :: (QueryParam param) => Text -> param
1300queryFlag name = queryParam name (Nothing :: Maybe ())
1487queryFlag name = queryParam name (Nothing :: Maybe ())
1489+-- | Construct query parameters from a 'ToForm' instance. This function
1490+-- produces the same query params as 'Form.urlEncodeAsFormStable'.
1492+-- Note that 'Form.Form' doesn't have the concept of parameters with the
1493+-- empty value (i.e. what you can get by @key =: ""@). If the value is
1494+-- empty, it will be encoded as a valueless parameter (i.e. what you can get
1495+-- by @queryFlag key@).
1498+formToQuery :: (QueryParam param, Monoid param, ToForm f) => f -> param
1499+formToQuery f = mconcat . fmap toParam . Form.toListStable $ toForm f
1501+ toParam (key, val) =
1302-- | A type class for query-parameter-like things. The reason to have an
1507-- | A type class for query-parameter-like things. The reason to have an
1303-- overloaded 'queryParam' is to be able to use it as an 'Option' and as a
1508-- overloaded 'queryParam' is to be able to use it as an 'Option' and as a
1304-- 'FormUrlEncodedParam' when constructing form URL encoded request bodies.
1509-- 'FormUrlEncodedParam' when constructing form URL encoded request bodies.
@@ -1308,11 +1513,17 @@ class QueryParam param where
1308 -- 'Nothing', it won't be included at all (i.e. you create a flag this
1513 -- 'Nothing', it won't be included at all (i.e. you create a flag this
1309 -- way). It's recommended to use @('=:')@ and 'queryFlag' instead of this
1514 -- way). It's recommended to use @('=:')@ and 'queryFlag' instead of this
1310 -- method, because they are easier to read.
1515 -- method, because they are easier to read.
1311− queryParam :: ToHttpApiData a => Text -> Maybe a -> param
1516+ queryParam :: (ToHttpApiData a) => Text -> Maybe a -> param
1518+ -- | Get the query parameter names and values set by 'queryParam'.
1521+ queryParamToList :: param -> [(Text, Maybe Text)]
1313instance QueryParam (Option scheme) where
1523instance QueryParam (Option scheme) where
1314 queryParam name mvalue =
1524 queryParam name mvalue =
1315 withQueryParams ((:) (name, toQueryParam <$> mvalue))
1525 withQueryParams ((:) (name, toQueryParam <$> mvalue))
1526+ queryParamToList (Option f _) = fst $ appEndo f ([], L.defaultRequest)
1317----------------------------------------------------------------------------
1528----------------------------------------------------------------------------
1318-- Request—Optional parameters—Headers
1529-- Request—Optional parameters—Headers
@@ -1336,6 +1547,14 @@ attachHeader :: ByteString -> ByteString -> L.Request -> L.Request
1336attachHeader name value x =
1547attachHeader name value x =
1337 x {L.requestHeaders = (CI.mk name, value) : L.requestHeaders x}
1548 x {L.requestHeaders = (CI.mk name, value) : L.requestHeaders x}
1550+-- | Same as 'header', but with redacted values on print.
1553+headerRedacted :: ByteString -> ByteString -> Option scheme
1554+headerRedacted name value = withRequest $ \x ->
1555+ let y = attachHeader name value x
1556+ in y {L.redactHeaders = CI.mk name `S.insert` L.redactHeaders y}
1339----------------------------------------------------------------------------
1558----------------------------------------------------------------------------
1340-- Request—Optional parameters—Cookies
1559-- Request—Optional parameters—Cookies
@@ -1477,7 +1696,7 @@ customAuth = Option mempty . pure
1478-- | Specify the port to connect to explicitly. Normally, 'Url' you use
1697-- | Specify the port to connect to explicitly. Normally, 'Url' you use
1479-- determines the default port: @80@ for HTTP and @443@ for HTTPS. This
1698-- determines the default port: @80@ for HTTP and @443@ for HTTPS. This
1480−-- 'Option' allows to choose an arbitrary port overwriting the defaults.
1699+-- 'Option' allows us to choose an arbitrary port overwriting the defaults.
1481port :: Int -> Option scheme
1700port :: Int -> Option scheme
1482port n = withRequest $ \x ->
1701port n = withRequest $ \x ->
1483 x {L.port = n}
1702 x {L.port = n}
@@ -1492,8 +1711,8 @@ port n = withRequest $ \x ->
1493-- > decompress (const True)
1712-- > decompress (const True)
1494decompress ::
1713decompress ::
1495− -- | Predicate that is given MIME type, it
1714+ -- | Predicate that is given MIME type, it returns 'True' when content
1496− -- returns 'True' when content should be decompressed on the fly.
1715+ -- should be decompressed on the fly.
1497 (ByteString -> Bool) ->
1716 (ByteString -> Bool) ->
1498 Option scheme
1717 Option scheme
1499decompress f = withRequest $ \x ->
1718decompress f = withRequest $ \x ->
@@ -1524,6 +1743,7 @@ httpVersion major minor = withRequest $ \x ->
1525-- | Make a request and ignore the body of the response.
1744-- | Make a request and ignore the body of the response.
1526newtype IgnoreResponse = IgnoreResponse (L.Response ())
1745newtype IgnoreResponse = IgnoreResponse (L.Response ())
1528instance HttpResponse IgnoreResponse where
1748instance HttpResponse IgnoreResponse where
1529 type HttpResponseBody IgnoreResponse = ()
1749 type HttpResponseBody IgnoreResponse = ()
@@ -1540,8 +1760,9 @@ ignoreResponse = Proxy
1540-- monad in which you use 'req' will determine what to do in the case when
1760-- monad in which you use 'req' will determine what to do in the case when
1541-- parsing fails (the 'JsonHttpException' constructor will be used).
1761-- parsing fails (the 'JsonHttpException' constructor will be used).
1542newtype JsonResponse a = JsonResponse (L.Response a)
1762newtype JsonResponse a = JsonResponse (L.Response a)
1544−instance FromJSON a => HttpResponse (JsonResponse a) where
1765+instance (FromJSON a) => HttpResponse (JsonResponse a) where
1545 type HttpResponseBody (JsonResponse a) = a
1766 type HttpResponseBody (JsonResponse a) = a
1546 toVanillaResponse (JsonResponse r) = r
1767 toVanillaResponse (JsonResponse r) = r
1547 getHttpResponse r = do
1768 getHttpResponse r = do
@@ -1559,6 +1780,7 @@ jsonResponse = Proxy
1559-- | Make a request and interpret the body of the response as a strict
1780-- | Make a request and interpret the body of the response as a strict
1560-- 'ByteString'.
1781-- 'ByteString'.
1561newtype BsResponse = BsResponse (L.Response ByteString)
1782newtype BsResponse = BsResponse (L.Response ByteString)
1563instance HttpResponse BsResponse where
1785instance HttpResponse BsResponse where
1564 type HttpResponseBody BsResponse = ByteString
1786 type HttpResponseBody BsResponse = ByteString
@@ -1575,6 +1797,7 @@ bsResponse = Proxy
1575-- | Make a request and interpret the body of the response as a lazy
1797-- | Make a request and interpret the body of the response as a lazy
1576-- 'BL.ByteString'.
1798-- 'BL.ByteString'.
1577newtype LbsResponse = LbsResponse (L.Response BL.ByteString)
1799newtype LbsResponse = LbsResponse (L.Response BL.ByteString)
1579instance HttpResponse LbsResponse where
1802instance HttpResponse LbsResponse where
1580 type HttpResponseBody LbsResponse = BL.ByteString
1803 type HttpResponseBody LbsResponse = BL.ByteString
@@ -1591,7 +1814,7 @@ lbsResponse = Proxy
1591----------------------------------------------------------------------------
1814----------------------------------------------------------------------------
1592-- Helpers for response interpretations
1815-- Helpers for response interpretations
1594−-- | Fetch beginning of response and return it together with new
1817+-- | Fetch beginning of the response and return it together with a new
1595-- @'L.Response' 'L.BodyReader'@ that can be passed to 'getHttpResponse' and
1818-- @'L.Response' 'L.BodyReader'@ that can be passed to 'getHttpResponse' and
1597grabPreview ::
1820grabPreview ::
@@ -1655,14 +1878,14 @@ brReadN br n = go 0 id id
1656-- | Get the response body.
1879-- | Get the response body.
1657responseBody ::
1880responseBody ::
1658− HttpResponse response =>
1881+ (HttpResponse response) =>
1659 response ->
1882 response ->
1660 HttpResponseBody response
1883 HttpResponseBody response
1661responseBody = L.responseBody . toVanillaResponse
1884responseBody = L.responseBody . toVanillaResponse
1663-- | Get the response status code.
1886-- | Get the response status code.
1664responseStatusCode ::
1887responseStatusCode ::
1665− HttpResponse response =>
1888+ (HttpResponse response) =>
1666 response ->
1889 response ->
1668responseStatusCode =
1891responseStatusCode =
@@ -1670,7 +1893,7 @@ responseStatusCode =
1671-- | Get the response status message.
1894-- | Get the response status message.
1672responseStatusMessage ::
1895responseStatusMessage ::
1673− HttpResponse response =>
1896+ (HttpResponse response) =>
1674 response ->
1897 response ->
1675 ByteString
1898 ByteString
1676responseStatusMessage =
1899responseStatusMessage =
@@ -1678,7 +1901,7 @@ responseStatusMessage =
1679-- | Lookup a particular header from a response.
1902-- | Lookup a particular header from a response.
1680responseHeader ::
1903responseHeader ::
1681− HttpResponse response =>
1904+ (HttpResponse response) =>
1682 -- | Response interpretation
1905 -- | Response interpretation
1683 response ->
1906 response ->
1684 -- | Header to lookup
1907 -- | Header to lookup
@@ -1690,7 +1913,7 @@ responseHeader r h =
1691-- | Get the response 'L.CookieJar'.
1914-- | Get the response 'L.CookieJar'.
1692responseCookieJar ::
1915responseCookieJar ::
1693− HttpResponse response =>
1916+ (HttpResponse response) =>
1694 response ->
1917 response ->
1695 L.CookieJar
1918 L.CookieJar
1696responseCookieJar = L.responseCookieJar . toVanillaResponse
1919responseCookieJar = L.responseCookieJar . toVanillaResponse
@@ -1703,9 +1926,9 @@ responseCookieJar = L.responseCookieJar . toVanillaResponse
1703-- To create a new response interpretation you just need to make your data
1926-- To create a new response interpretation you just need to make your data
1704-- type an instance of the 'HttpResponse' type class.
1927-- type an instance of the 'HttpResponse' type class.
1706−-- | A type class for response interpretations. It allows to describe how to
1929+-- | A type class for response interpretations. It allows us to describe how
1707−-- consume response from a @'L.Response' 'L.BodyReader'@ and produce the
1930+-- to consume the response from a @'L.Response' 'L.BodyReader'@ and produce
1708−-- final result that is to be returned to the user.
1931+-- the final result that is to be returned to the user.
1709class HttpResponse response where
1932class HttpResponse response where
1710 -- | The associated type is the type of body that can be extracted from an
1933 -- | The associated type is the type of body that can be extracted from an
1711 -- instance of 'HttpResponse'.
1934 -- instance of 'HttpResponse'.
@@ -1744,6 +1967,16 @@ class HttpResponse response where
1744 acceptHeader :: Proxy response -> Maybe ByteString
1967 acceptHeader :: Proxy response -> Maybe ByteString
1745 acceptHeader Proxy = Nothing
1968 acceptHeader Proxy = Nothing
1970+-- | This instance has been added to make it easier to inspect 'L.Response'
1971+-- using Req's functions like 'responseStatusCode', 'responseStatusMessage',
1975+instance HttpResponse (L.Response ()) where
1976+ type HttpResponseBody (L.Response ()) = ()
1977+ toVanillaResponse = id
1978+ getHttpResponse = return . void
1747----------------------------------------------------------------------------
1980----------------------------------------------------------------------------
@@ -1769,7 +2002,7 @@ class RequestComponent a where
1769-- method@ and @'HttpBody' body => 'RequestComponent' body@ when it decides
2002-- method@ and @'HttpBody' body => 'RequestComponent' body@ when it decides
1770-- which instance to use (i.e. the constraints are taken into account later,
2003-- which instance to use (i.e. the constraints are taken into account later,
1771-- when instance is already chosen).
2004-- when instance is already chosen).
1772−newtype Womb (tag :: Symbol) a = Womb a
2005+newtype Tagged (tag :: Symbol) a = Tagged a
1774-- | Exceptions that this library throws.
2007-- | Exceptions that this library throws.
1775data HttpException
2008data HttpException
@@ -1778,10 +2011,24 @@ data HttpException
1778 | -- | A wrapper with Aeson-produced 'String' describing why decoding
2011 | -- | A wrapper with Aeson-produced 'String' describing why decoding
1779 -- failed
2012 -- failed
1780 JsonHttpException String
2013 JsonHttpException String
1781− deriving (Show, Typeable, Generic)
2014+ deriving (Show, Generic)
1783instance Exception HttpException
2016instance Exception HttpException
2018+-- | Return 'Just' if the given 'HttpException' is wrapping a http-client's
2019+-- 'L.StatusCodeException'. Otherwise, return 'Nothing'.
2022+isStatusCodeException :: HttpException -> Maybe (L.Response ())
2023+isStatusCodeException
2024+ ( VanillaHttpException
2025+ ( L.HttpExceptionRequest
2027+ (L.StatusCodeException r _)
2030+isStatusCodeException _ = Nothing
1785-- | A simple type isomorphic to 'Bool' that we only have for better error
2032-- | A simple type isomorphic to 'Bool' that we only have for better error
1786-- messages. We use it as a kind and its data constructors as type-level
2033-- messages. We use it as a kind and its data constructors as type-level
@@ -1801,11 +2048,4 @@ data Scheme
1802 | -- | HTTPS
2049 | -- | HTTPS
1804− deriving (Eq, Ord, Show, Data, Typeable, Generic, TH.Lift)
2051+ deriving (Eq, Ord, Show, Data, Generic, TH.Lift)
1806−----------------------------------------------------------------------------
1809−-- | Max length of preview fragment of response body.
1810−bodyPreviewLength :: Num a => a
1811−bodyPreviewLength = 1024