@@ -8,7 +8,7 @@
8-- Portability : portable
8-- Portability : portable
10-- This is an easy-to-use, type-safe, expandable, high-level HTTP library
10-- This is an easy-to-use, type-safe, expandable, high-level HTTP library
11−-- that just works without fooling around.
11+-- that just works without any fooling around.
13-- /(A modest intro goes here, click on 'req' to start making requests.)/
13-- /(A modest intro goes here, click on 'req' to start making requests.)/
@@ -19,19 +19,17 @@
19-- currently modify 'L.ManagerSettings' of default manager because the
19-- currently modify 'L.ManagerSettings' of default manager because the
20-- library always use the same implicit global manager for simplicity and
20-- library always use the same implicit global manager for simplicity and
21-- maximal connection sharing. There is a way to use your own manager with
21-- maximal connection sharing. There is a way to use your own manager with
22−-- different settings, but it requires a bit more typing. Just like with my
22+-- different settings, but it requires a bit more typing. Doing HTTP
23−-- other library, Megaparsec, I spent considerable amount of time working on
24−-- the documentation and examples, because doing HTTP requests is a common
25−-- task and Haskell library for this should be very approachable and clear
23+-- requests is a common task and Haskell library for this should be very
26−-- to beginners.
24+-- approachable and clear to beginners.
28-- “Type-safe” means that the library is protective and eliminates certain
26-- “Type-safe” means that the library is protective and eliminates certain
29-- class of errors compared to alternative libraries like @wreq@ or vanilla
27-- class of errors compared to alternative libraries like @wreq@ or vanilla
30−-- @http-client@. For example it makes sure user does not send request body
28+-- @http-client@. For example it makes sure that user does not send request
31−-- when using methods like 'GET' or 'DELETE', minimizes amount of implicit
29+-- body when using methods like 'GET' or 'DELETE', minimizes amount of
32−-- assumptions making user specify his\/her intentions in explicit form (for
30+-- implicit assumptions making user specify his\/her intentions in explicit
33−-- example it's not possible to avoid specifying body or method of a
31+-- form (for example it's not possible to avoid specifying body or method of
34−-- request). It carefully hides underlying types from lower-level
32+-- a request). It carefully hides underlying types from lower-level
35-- @http-client@ package because it's not type safe enough (for example
33-- @http-client@ package because it's not type safe enough (for example
36-- 'L.Request' is an instance of 'Data.String.IsString' and if it's
34-- 'L.Request' is an instance of 'Data.String.IsString' and if it's
37-- malformed, it will blow up at run-time).
35-- malformed, it will blow up at run-time).
@@ -39,10 +37,10 @@
39-- “Expandable” refers to the ability of the library to be expanded without
37-- “Expandable” refers to the ability of the library to be expanded without
40-- ugly hacking. For example it's possible to define your own HTTP methods,
38-- ugly hacking. For example it's possible to define your own HTTP methods,
41-- new ways to construct body of request, new authorization options, new
39-- new ways to construct body of request, new authorization options, new
42−-- ways to actually perform request and how to represent\/parse it. As user
40+-- ways to actually perform request and how to represent\/parse its
43−-- extends the library to satisfy his\/her special needs, the new solutions
41+-- response. As user extends the library to satisfy his\/her special needs,
44−-- work just like built-ins. That said, all common cases are covered by the
42+-- the new solutions work just like built-ins. That said, all common cases
45−-- library out-of-the-box.
43+-- are covered by the library out-of-the-box.
47-- “High-level” means that there are less details to worry about. The
45-- “High-level” means that there are less details to worry about. The
48-- library is a result of my experiences as a Haskell consultant, working
46-- library is a result of my experiences as a Haskell consultant, working
@@ -52,12 +50,12 @@
52-- concerned with purity: just define 'handleHttpException' accordingly when
50-- concerned with purity: just define 'handleHttpException' accordingly when
53-- making your monad instance of 'MonadHttp' and it will play seamlessly.
51-- making your monad instance of 'MonadHttp' and it will play seamlessly.
54-- Finally, the library cuts boilerplate considerably and helps write
52-- Finally, the library cuts boilerplate considerably and helps write
55−-- concise, easy to read code, thanks to its minimal and very uniform API.
53+-- concise, easy to read code, thanks to its minimal and uniform API.
57-- The documentation below is structured in such a way that most important
55-- The documentation below is structured in such a way that most important
58-- information goes first: you learn how to do HTTP requests, then how to
56-- information goes first: you learn how to do HTTP requests, then how to
59−-- embed them any monad you have, then it goes on giving you details about
57+-- embed them in any monad you have, then it goes on giving you details
60−-- less-common things you may want to know about. The documentation is
58+-- about less-common things you may want to know about. The documentation is
61-- written with sufficient coverage of details and examples, it's designed
59-- written with sufficient coverage of details and examples, it's designed
62-- to be a complete tutorial on its own.
60-- to be a complete tutorial on its own.
@@ -68,7 +66,7 @@
68-- * <https://hackage.haskell.org/package/http-client> — low level HTTP
66-- * <https://hackage.haskell.org/package/http-client> — low level HTTP
69-- client used everywhere in Haskell.
67-- client used everywhere in Haskell.
70-- * <https://hackage.haskell.org/package/http-client-tls> — TLS (HTTPS)
68-- * <https://hackage.haskell.org/package/http-client-tls> — TLS (HTTPS)
71−-- support.
69+-- support for @http-client@.
72-- * <https://hackage.haskell.org/package/http-conduit> — conduit
70-- * <https://hackage.haskell.org/package/http-conduit> — conduit
73-- interface to @http-client@.
71-- interface to @http-client@.
@@ -80,15 +78,11 @@
80{-# LANGUAGE DeriveDataTypeable #-}
78{-# LANGUAGE DeriveDataTypeable #-}
81{-# LANGUAGE DeriveGeneric #-}
79{-# LANGUAGE DeriveGeneric #-}
82{-# LANGUAGE FlexibleInstances #-}
80{-# LANGUAGE FlexibleInstances #-}
83−{-# LANGUAGE GADTs #-}
84{-# LANGUAGE GeneralizedNewtypeDeriving #-}
81{-# LANGUAGE GeneralizedNewtypeDeriving #-}
85{-# LANGUAGE KindSignatures #-}
82{-# LANGUAGE KindSignatures #-}
86−{-# LANGUAGE MultiParamTypeClasses #-}
87−{-# LANGUAGE OverloadedStrings #-}
88{-# LANGUAGE RecordWildCards #-}
83{-# LANGUAGE RecordWildCards #-}
89{-# LANGUAGE ScopedTypeVariables #-}
84{-# LANGUAGE ScopedTypeVariables #-}
90{-# LANGUAGE TypeFamilies #-}
85{-# LANGUAGE TypeFamilies #-}
91−{-# LANGUAGE UndecidableInstances #-}
92{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
86{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
94module Network.HTTP.Req
88module Network.HTTP.Req
@@ -151,12 +145,13 @@ import Data.Typeable (Typeable)
151import GHC.Generics
145import GHC.Generics
152import GHC.TypeLits
146import GHC.TypeLits
153import System.IO.Unsafe (unsafePerformIO)
147import System.IO.Unsafe (unsafePerformIO)
154−import qualified Data.ByteString as B
148+import qualified Data.ByteString as B
155−import qualified Data.ByteString.Lazy as BL
149+import qualified Data.ByteString.Lazy as BL
156−import qualified Network.Connection as NC
150+import qualified Network.Connection as NC
157−import qualified Network.HTTP.Client as L
151+import qualified Network.HTTP.Client as L
158−import qualified Network.HTTP.Client.TLS as L
152+import qualified Network.HTTP.Client.Internal as LI
153+import qualified Network.HTTP.Client.TLS as L
159−import qualified Network.HTTP.Types as Y
154+import qualified Network.HTTP.Types as Y
161----------------------------------------------------------------------------
156----------------------------------------------------------------------------
162-- Making a request
157-- Making a request
@@ -193,24 +188,17 @@ req method url body options = do
193 liftIO (try $ getHttpResponse manager request)
188 liftIO (try $ getHttpResponse manager request)
194 >>= either handleHttpException return
189 >>= either handleHttpException return
196−----------------------------------------------------------------------------
197−-- Embedding requests into your monad
199−-- $embedding-requests
201−-- To use 'req' in your monad, all you need to do is to make it an instance
202−-- of the 'MonadHttp' type class, which see.
204-- | Global 'L.Manager' that 'req' uses. Here we just go with the default
191-- | Global 'L.Manager' that 'req' uses. Here we just go with the default
205-- settings, so users don't need to deal with this manager stuff at all, but
192-- settings, so users don't need to deal with this manager stuff at all, but
206-- when we create a request, instance 'HttpConfig' can affect the default
193-- when we create a request, instance 'HttpConfig' can affect the default
207-- settings via 'getHttpConfig'.
194-- settings via 'getHttpConfig'.
209−-- A note about safety in case 'unsafePerformIO' looks suspicious to you.
196+-- A note about safety, in case 'unsafePerformIO' looks suspicious to you.
210-- The value of 'globalManager' is named and lives on top level. This means
197-- The value of 'globalManager' is named and lives on top level. This means
211-- it will be shared, i.e. computed only once on first use of manager. From
198-- it will be shared, i.e. computed only once on first use of manager. From
212-- that moment on the 'IORef' will be just reused — exactly the behaviour we
199-- that moment on the 'IORef' will be just reused — exactly the behaviour we
213−-- want here in order to maximize connection sharing.
200+-- want here in order to maximize connection sharing. GHC could spoil the
201+-- plan by inlining the definition, hence the @NOINLINE@ pragma.
215globalManager :: IORef L.Manager
203globalManager :: IORef L.Manager
216globalManager = unsafePerformIO $ do
204globalManager = unsafePerformIO $ do
@@ -220,6 +208,14 @@ globalManager = unsafePerformIO $ do
220 newIORef manager
208 newIORef manager
221{-# NOINLINE globalManager #-}
209{-# NOINLINE globalManager #-}
211+----------------------------------------------------------------------------
212+-- Embedding requests into your monad
214+-- $embedding-requests
216+-- To use 'req' in your monad, all you need to do is to make the monad an
217+-- instance of the 'MonadHttp' type class, which see.
223-- | A type class for monads that support performing HTTP requests.
219-- | A type class for monads that support performing HTTP requests.
224-- Typically, you only need to define the 'handleHttpException' method
220-- Typically, you only need to define the 'handleHttpException' method
225-- unless you want to tweak 'HttpConfig'.
221-- unless you want to tweak 'HttpConfig'.
@@ -257,18 +253,23 @@ data HttpConfig = HttpConfig
257 , httpConfigRedirectCount :: Word
253 , httpConfigRedirectCount :: Word
258 -- ^ How many redirects to follow when getting a resource. Default
254 -- ^ How many redirects to follow when getting a resource. Default
259 -- value: 10.
255 -- value: 10.
256+ , httpConfigAltManager :: Maybe L.Manager
257+ -- ^ Alternative 'L.Manager' to use. 'Nothing' (default value) means
258+ -- that default implicit manager will be used (that's what you want in
260− } deriving (Show, Read, Eq, Ord, Typeable, Generic)
260+ } deriving Typeable
261− -- ↑ NOTE We can't derive 'Data' here because of 'L.Proxy'.
263instance Default HttpConfig where
262instance Default HttpConfig where
264 def = HttpConfig
263 def = HttpConfig
265 { httpConfigProxy = Nothing
264 { httpConfigProxy = Nothing
266− , httpConfigRedirectCount = 10 }
265+ , httpConfigRedirectCount = 10
266+ , httpConfigAltManager = Nothing }
268instance RequestComponent HttpConfig where
268instance RequestComponent HttpConfig where
269 getRequestMod HttpConfig {..} = Endo $ \x ->
269 getRequestMod HttpConfig {..} = Endo $ \x ->
270− x { L.proxy = httpConfigProxy
270+ x { L.proxy = httpConfigProxy
271− , L.redirectCount = fromIntegral httpConfigRedirectCount }
271+ , L.redirectCount = fromIntegral httpConfigRedirectCount
272+ , LI.requestManagerOverride = httpConfigAltManager }
273----------------------------------------------------------------------------
274----------------------------------------------------------------------------
274-- Request — Methods
275-- Request — Methods
@@ -376,9 +377,6 @@ class HttpMethod a where
377 httpMethodName :: Proxy a -> Y.Method
378 httpMethodName :: Proxy a -> Y.Method
379−-- NOTE Now we state how to get an endomorphism on 'Request's that changes
380−-- given 'Request' so it has the specified method.
382instance HttpMethod method => RequestComponent (Womb "method" method) where
380instance HttpMethod method => RequestComponent (Womb "method" method) where
383 getRequestMod _ = Endo $ \x ->
381 getRequestMod _ = Endo $ \x ->
384 x { L.method = httpMethodName (Proxy :: Proxy method) }
382 x { L.method = httpMethodName (Proxy :: Proxy method) }