on master help sign in
Improve the documentation
1d7763fmrkkrp
Network/HTTP/Req.hs+97−89
@@ -38,8 +38,8 @@
38-- methods like 'GET' or 'OPTIONS', and the amount of implicit assumptions
38-- methods like 'GET' or 'OPTIONS', and the amount of implicit assumptions
39-- is minimized by making the user specify his\/her intentions in an
39-- is minimized by making the user specify his\/her intentions in an
40-- explicit form (for example, it's not possible to avoid specifying the
40-- explicit form (for example, it's not possible to avoid specifying the
41−-- body or method of a request). Authentication methods that assume TLS
41+-- body or method of a request). Authentication methods that assume HTTPS
42−-- force the user to use TLS at the type level. The library also carefully
42+-- force the user to use HTTPS at the type level. The library also carefully
43-- hides underlying types from the lower-level @http-client@ package because
43-- hides underlying types from the lower-level @http-client@ package because
44-- those types are not safe enough (for example 'L.Request' is an instance
44-- those types are not safe enough (for example 'L.Request' is an instance
45-- of 'Data.String.IsString' and, if it's malformed, it will blow up at
45-- of 'Data.String.IsString' and, if it's malformed, it will blow up at
@@ -76,12 +76,11 @@
76-- === Lightweight, no risk solution
76-- === Lightweight, no risk solution
77--
77--
78-- The library uses the following mature packages under the hood to
78-- The library uses the following mature packages under the hood to
79−-- guarantee you the best experience that doesn't have any bugs or other
79+-- guarantee you the best experience:
80−-- funny business:
81--
80--
82−-- * <https://hackage.haskell.org/package/http-client> — low level HTTP
81+-- * <https://hackage.haskell.org/package/http-client>—low level HTTP
83-- client used everywhere in Haskell.
82-- client used everywhere in Haskell.
84−-- * <https://hackage.haskell.org/package/http-client-tls> — TLS (HTTPS)
83+-- * <https://hackage.haskell.org/package/http-client-tls>—TLS (HTTPS)
85-- support for @http-client@.
84-- support for @http-client@.
86--
85--
87-- It's important to note that since we leverage well-known libraries that
86-- It's important to note that since we leverage well-known libraries that
@@ -226,6 +225,7 @@ import Data.List.NonEmpty (NonEmpty (..))
226import Data.Maybe (fromMaybe)
225import Data.Maybe (fromMaybe)
227import Data.Proxy
226import Data.Proxy
228import Data.Semigroup hiding (Option, option)
227import Data.Semigroup hiding (Option, option)
228+import Data.Text (Text)
229import Data.Typeable (Typeable)
229import Data.Typeable (Typeable)
230import GHC.Generics
230import GHC.Generics
231import GHC.TypeLits
231import GHC.TypeLits
@@ -237,7 +237,6 @@ import qualified Data.ByteString as B
237import qualified Data.ByteString.Lazy as BL
237import qualified Data.ByteString.Lazy as BL
238import qualified Data.CaseInsensitive as CI
238import qualified Data.CaseInsensitive as CI
239import qualified Data.List.NonEmpty as NE
239import qualified Data.List.NonEmpty as NE
240−import qualified Data.Text as T
241import qualified Data.Text.Encoding as T
240import qualified Data.Text.Encoding as T
242import qualified Network.Connection as NC
241import qualified Network.Connection as NC
243import qualified Network.HTTP.Client as L
242import qualified Network.HTTP.Client as L
@@ -277,22 +276,26 @@ import GHC.Exts (Constraint)
277-- tutorial has a section about HTTP bodies, but usage is very
276-- tutorial has a section about HTTP bodies, but usage is very
278-- straightforward and should be clear from the examples below.
277-- straightforward and should be clear from the examples below.
279--
278--
280−-- @response@ is a type hint how to make and interpret response of HTTP
279+-- @response@ is a type hint how to make and interpret response of an HTTP
281−-- request, out-of-the-box it can be the following: 'ignoreResponse',
280+-- request. Out-of-the-box it can be the following:
281+--
282+-- * 'ignoreResponse'
283+-- * 'jsonResponse'
282−-- 'jsonResponse', 'bsResponse' (to get strict 'ByteString'), 'lbsResponse'
284+-- * 'bsResponse' (to get a strict 'ByteString')
285+-- * 'lbsResponse' (to get a lazy 'BL.ByteString')
283−-- (to get lazy 'BL.ByteString'), and 'returnRequest' (makes no request,
286+-- * 'returnRequest' (makes no request, but returns the constructed
284−-- just returns response, used for testing).
287+-- request itself, used for testing).
285--
288--
286-- Finally @options@ is a 'Monoid' that holds a composite 'Option' for all
289-- Finally @options@ is a 'Monoid' that holds a composite 'Option' for all
287−-- other optional things like query parameters, headers, non-standard port
290+-- other optional settings like query parameters, headers, non-standard port
288−-- number, etc. There are quite a few things you can put there, see
291+-- number, etc. There are quite a few things you can put there, see the
289-- corresponding section in the documentation. If you don't need anything at
292-- corresponding section in the documentation. If you don't need anything at
290-- all, pass 'mempty'.
293-- all, pass 'mempty'.
291--
294--
292-- __Note__ that if you use 'req' to do all your requests, connection
295-- __Note__ that if you use 'req' to do all your requests, connection
293-- sharing and reuse is done for you automatically.
296-- sharing and reuse is done for you automatically.
294--
297--
295−-- See the examples below to get on the speed very quickly.
298+-- See the examples below to get on the speed quickly.
296--
299--
297-- ==== __Examples__
300-- ==== __Examples__
298--
301--
@@ -390,7 +393,7 @@ req
390 , HttpResponse response
393 , HttpResponse response
391 , HttpBodyAllowed (AllowsBody method) (ProvidesBody body) )
394 , HttpBodyAllowed (AllowsBody method) (ProvidesBody body) )
392 => method -- ^ HTTP method
395 => method -- ^ HTTP method
393− -> Url scheme -- ^ 'Url' — location of resource
396+ -> Url scheme -- ^ 'Url'—location of resource
394 -> body -- ^ Body of the request
397 -> body -- ^ Body of the request
395 -> Proxy response -- ^ A hint how to interpret response
398 -> Proxy response -- ^ A hint how to interpret response
396 -> Option scheme -- ^ Collection of optional parameters
399 -> Option scheme -- ^ Collection of optional parameters
@@ -403,11 +406,11 @@ req method url body Proxy options = do
403 nubHeaders = Endo $ \x ->
406 nubHeaders = Endo $ \x ->
404 x { L.requestHeaders = nubBy ((==) `on` fst) (L.requestHeaders x) }
407 x { L.requestHeaders = nubBy ((==) `on` fst) (L.requestHeaders x) }
405 request' = flip appEndo L.defaultRequest $
408 request' = flip appEndo L.defaultRequest $
406− -- NOTE Order of 'mappend's matters, here method is overwritten first
409+ -- NOTE The order of 'mappend's matters, here method is overwritten
407− -- and 'options' take effect last. In particular, this means that
410+ -- first and 'options' take effect last. In particular, this means
408− -- 'options' can overwrite things set by other request components,
411+ -- that 'options' can overwrite things set by other request
409− -- which is useful for setting port number, "Content-Type" header,
412+ -- components, which is useful for setting port number,
410− -- etc.
413+ -- "Content-Type" header, etc.
411 nubHeaders <>
414 nubHeaders <>
412 getRequestMod options <>
415 getRequestMod options <>
413 getRequestMod config <>
416 getRequestMod config <>
@@ -426,10 +429,10 @@ req method url body Proxy options = do
426--
429--
427-- A note about safety, in case 'unsafePerformIO' looks suspicious to you.
430-- A note about safety, in case 'unsafePerformIO' looks suspicious to you.
428-- The value of 'globalManager' is named and lives on top level. This means
431-- The value of 'globalManager' is named and lives on top level. This means
429−-- it will be shared, i.e. computed only once on first use of manager. From
432+-- it will be shared, i.e. computed only once on the first use of the
430−-- that moment on the 'IORef' will be just reused — exactly the behavior we
433+-- manager. From that moment on the 'IORef' will be just reused—exactly the
431−-- want here in order to maximize connection sharing. GHC could spoil the
434+-- behavior we want here in order to maximize connection sharing. GHC could
432−-- plan by inlining the definition, hence the @NOINLINE@ pragma.
435+-- spoil the plan by inlining the definition, hence the @NOINLINE@ pragma.
433
436
434globalManager :: IORef L.Manager
437globalManager :: IORef L.Manager
435globalManager = unsafePerformIO $ do
438globalManager = unsafePerformIO $ do
@@ -456,6 +459,8 @@ withReqManager m = liftIO (readIORef globalManager) >>= m
456--
459--
457-- When writing a library, keep your API polymorphic in terms of
460-- When writing a library, keep your API polymorphic in terms of
458-- 'MonadHttp', only define instance of 'MonadHttp' in final application.
461-- 'MonadHttp', only define instance of 'MonadHttp' in final application.
462+-- Another option is to use @newtype@ wrapped monad stack and define
463+-- 'MonadHttp' for it.
459
464
460-- | A type class for monads that support performing HTTP requests.
465-- | A type class for monads that support performing HTTP requests.
461-- Typically, you only need to define the 'handleHttpException' method
466-- Typically, you only need to define the 'handleHttpException' method
@@ -528,12 +533,12 @@ instance RequestComponent HttpConfig where
528 , LI.checkResponse = httpConfigCheckResponse }
533 , LI.checkResponse = httpConfigCheckResponse }
529
534
530----------------------------------------------------------------------------
535----------------------------------------------------------------------------
531−-- Request — Method
536+-- Request—Method
532
537
533-- $method
538-- $method
534--
539--
535-- The package supports all methods as defined by RFC 2616, and 'PATCH'
540-- The package supports all methods as defined by RFC 2616, and 'PATCH'
536−-- which is defined by RFC 5789 — that should be enough to talk to RESTful
541+-- which is defined by RFC 5789—that should be enough to talk to RESTful
537-- APIs. In some cases, however, you may want to add more methods (e.g. you
542-- APIs. In some cases, however, you may want to add more methods (e.g. you
538-- work with WebDAV <https://en.wikipedia.org/wiki/WebDAV>); no need to
543-- work with WebDAV <https://en.wikipedia.org/wiki/WebDAV>); no need to
539-- compromise on type safety and hack, it only takes a couple of seconds to
544-- compromise on type safety and hack, it only takes a couple of seconds to
@@ -572,7 +577,7 @@ instance HttpMethod PUT where
572 httpMethodName Proxy = Y.methodPut
577 httpMethodName Proxy = Y.methodPut
573
578
574-- | 'DELETE' method. This data type does not allow having request body with
579-- | 'DELETE' method. This data type does not allow having request body with
575−-- 'DELETE' requests, as it should be, however some APIs may expect 'DELETE'
580+-- 'DELETE' requests, as it should be. However some APIs may expect 'DELETE'
576-- requests to have bodies, in that case define your own variation of
581-- requests to have bodies, in that case define your own variation of
577-- 'DELETE' method and allow it to have a body.
582-- 'DELETE' method and allow it to have a body.
578
583
@@ -625,10 +630,10 @@ instance HttpMethod PATCH where
625
630
626class HttpMethod a where
631class HttpMethod a where
627
632
628− -- | Type function 'AllowsBody' returns type of kind 'CanHaveBody' which
633+ -- | Type function 'AllowsBody' returns a type of kind 'CanHaveBody' which
629 -- tells the rest of the library whether the method can have a body or
634 -- tells the rest of the library whether the method can have a body or
630− -- not. We use the special type 'CanHaveBody' “lifted” into kind instead
635+ -- not. We use the special type 'CanHaveBody' “lifted” to kind level
631− -- of 'Bool' to get more user-friendly compiler messages.
636+ -- instead of 'Bool' to get more user-friendly compiler messages.
632
637
633 type AllowsBody a :: CanHaveBody
638 type AllowsBody a :: CanHaveBody
634
639
@@ -641,7 +646,7 @@ instance HttpMethod method => RequestComponent (Womb "method" method) where
641 x { L.method = httpMethodName (Proxy :: Proxy method) }
646 x { L.method = httpMethodName (Proxy :: Proxy method) }
642
647
643----------------------------------------------------------------------------
648----------------------------------------------------------------------------
644−-- Request — URL
649+-- Request—URL
645
650
646-- $url
651-- $url
647--
652--
@@ -650,7 +655,7 @@ instance HttpMethod method => RequestComponent (Womb "method" method) where
650
655
651-- | Request's 'Url'. Start constructing your 'Url' with 'http' or 'https'
656-- | Request's 'Url'. Start constructing your 'Url' with 'http' or 'https'
652-- specifying the scheme and host at the same time. Then use the @('/~')@
657-- specifying the scheme and host at the same time. Then use the @('/~')@
653−-- and @('/:')@ operators to grow path one piece at a time. Every single
658+-- and @('/:')@ operators to grow the path one piece at a time. Every single
654-- piece of path will be url(percent)-encoded, so using @('/~')@ and
659-- piece of path will be url(percent)-encoded, so using @('/~')@ and
655-- @('/:')@ is the only way to have forward slashes between path segments.
660-- @('/:')@ is the only way to have forward slashes between path segments.
656-- This approach makes working with dynamic path segments easy and safe. See
661-- This approach makes working with dynamic path segments easy and safe. See
@@ -677,20 +682,20 @@ instance HttpMethod method => RequestComponent (Womb "method" method) where
677-- > https "юникод.рф"
682-- > https "юникод.рф"
678-- > -- https://%D1%8E%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4.%D1%80%D1%84
683-- > -- https://%D1%8E%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4.%D1%80%D1%84
679
684
680−data Url (scheme :: Scheme) = Url Scheme (NonEmpty T.Text)
685+data Url (scheme :: Scheme) = Url Scheme (NonEmpty Text)
681− -- NOTE The second value is path segments in reversed order.
686+ -- NOTE The second value is the path segments in reversed order.
682 deriving (Eq, Ord, Show, Data, Typeable, Generic)
687 deriving (Eq, Ord, Show, Data, Typeable, Generic)
683
688
684-- | Given host name, produce a 'Url' which have “http” as its scheme and
689-- | Given host name, produce a 'Url' which have “http” as its scheme and
685-- empty path. This also sets port to @80@.
690-- empty path. This also sets port to @80@.
686
691
687−http :: T.Text -> Url 'Http
692+http :: Text -> Url 'Http
688http = Url Http . pure
693http = Url Http . pure
689
694
690-- | Given host name, produce a 'Url' which have “https” as its scheme and
695-- | Given host name, produce a 'Url' which have “https” as its scheme and
691-- empty path. This also sets port to @443@.
696-- empty path. This also sets port to @443@.
692
697
693−https :: T.Text -> Url 'Https
698+https :: Text -> Url 'Https
694https = Url Https . pure
699https = Url Https . pure
695
700
696-- | Grow given 'Url' appending a single path segment to it. Note that the
701-- | Grow given 'Url' appending a single path segment to it. Note that the
@@ -700,11 +705,11 @@ infixl 5 /~
700(/~) :: ToHttpApiData a => Url scheme -> a -> Url scheme
705(/~) :: ToHttpApiData a => Url scheme -> a -> Url scheme
701Url secure path /~ segment = Url secure (NE.cons (toUrlPiece segment) path)
706Url secure path /~ segment = Url secure (NE.cons (toUrlPiece segment) path)
702
707
703−-- | Type-constrained version of @('/~')@ to remove ambiguity in cases when
708+-- | Type-constrained version of @('/~')@ to remove ambiguity in the cases
704−-- next URL piece is a 'Text' literal.
709+-- when next URL piece is a 'Text' literal.
705
710
706infixl 5 /:
711infixl 5 /:
707−(/:) :: Url scheme -> T.Text -> Url scheme
712+(/:) :: Url scheme -> Text -> Url scheme
708(/:) = (/~)
713(/:) = (/~)
709
714
710-- | The 'parseUrlHttp' function provides an alternative method to get 'Url'
715-- | The 'parseUrlHttp' function provides an alternative method to get 'Url'
@@ -735,7 +740,7 @@ parseUrlHttps url' = do
735-- | Get host\/collection of path pieces and possibly query parameters
740-- | Get host\/collection of path pieces and possibly query parameters
736-- already converted to 'Option'. This function is not public.
741-- already converted to 'Option'. This function is not public.
737
742
738−parseUrlHelper :: ByteString -> Maybe (NonEmpty T.Text, Option scheme)
743+parseUrlHelper :: ByteString -> Maybe (NonEmpty Text, Option scheme)
739parseUrlHelper url = do
744parseUrlHelper url = do
740 let (path', query') = B.break (== 0x3f) url
745 let (path', query') = B.break (== 0x3f) url
741 query = mconcat (uncurry queryParam <$> Y.parseQueryText query')
746 query = mconcat (uncurry queryParam <$> Y.parseQueryText query')
@@ -756,13 +761,13 @@ instance RequestComponent (Url scheme) where
756 (BL.toStrict . BB.toLazyByteString . Y.encodePathSegments) path }
761 (BL.toStrict . BB.toLazyByteString . Y.encodePathSegments) path }
757
762
758----------------------------------------------------------------------------
763----------------------------------------------------------------------------
759−-- Request — Body
764+-- Request—Body
760
765
761-- $body
766-- $body
762--
767--
763-- A number of options for request bodies are available. The @Content-Type@
768-- A number of options for request bodies are available. The @Content-Type@
764−-- header is set for you automatically according to body option you use
769+-- header is set for you automatically according to the body option you use
765−-- (it's always specified in documentation for given body option). To add
770+-- (it's always specified in documentation for a given body option). To add
766-- your own way to represent request body, see 'HttpBody'.
771-- your own way to represent request body, see 'HttpBody'.
767
772
768-- | This data type represents empty body of an HTTP request. This is the
773-- | This data type represents empty body of an HTTP request. This is the
@@ -776,7 +781,7 @@ data NoReqBody = NoReqBody
776instance HttpBody NoReqBody where
781instance HttpBody NoReqBody where
777 getRequestBody NoReqBody = L.RequestBodyBS B.empty
782 getRequestBody NoReqBody = L.RequestBodyBS B.empty
778
783
779−-- | This body option allows to use a JSON object as request body — probably
784+-- | This body option allows to use a JSON object as request body—probably
780-- the most popular format right now. Just wrap a data type that is an
785-- the most popular format right now. Just wrap a data type that is an
781-- instance of 'ToJSON' type class and you are done: it will be converted to
786-- instance of 'ToJSON' type class and you are done: it will be converted to
782-- JSON and inserted as request body.
787-- JSON and inserted as request body.
@@ -839,7 +844,7 @@ instance HttpBody ReqBodyUrlEnc where
839-- | An opaque monoidal value that allows to collect URL-encoded parameters
844-- | An opaque monoidal value that allows to collect URL-encoded parameters
840-- to be wrapped in 'ReqBodyUrlEnc'.
845-- to be wrapped in 'ReqBodyUrlEnc'.
841
846
842−newtype FormUrlEncodedParam = FormUrlEncodedParam [(T.Text, Maybe T.Text)]
847+newtype FormUrlEncodedParam = FormUrlEncodedParam [(Text, Maybe Text)]
843 deriving (Semigroup, Monoid)
848 deriving (Semigroup, Monoid)
844
849
845instance QueryParam FormUrlEncodedParam where
850instance QueryParam FormUrlEncodedParam where
@@ -894,7 +899,7 @@ reqBodyMultipart parts = liftIO $ do
894 body <- LM.renderParts boundary parts
899 body <- LM.renderParts boundary parts
895 return (ReqBodyMultipart boundary body)
900 return (ReqBodyMultipart boundary body)
896
901
897−-- | A type class for things that can be interpreted as HTTP
902+-- | A type class for things that can be interpreted as an HTTP
898-- 'L.RequestBody'.
903-- 'L.RequestBody'.
899
904
900class HttpBody body where
905class HttpBody body where
@@ -921,8 +926,8 @@ type family ProvidesBody body :: CanHaveBody where
921 ProvidesBody body = 'CanHaveBody
926 ProvidesBody body = 'CanHaveBody
922
927
923-- | This type function allows any HTTP body if method says it
928-- | This type function allows any HTTP body if method says it
924−-- 'CanHaveBody'. When method says it should have 'NoBody', the only body
929+-- 'CanHaveBody'. When the method says it should have 'NoBody', the only
925−-- option to use is 'NoReqBody'.
930+-- body option to use is 'NoReqBody'.
926--
931--
927-- __Note__: users of GHC 8.0.1 and later will see a slightly more friendly
932-- __Note__: users of GHC 8.0.1 and later will see a slightly more friendly
928-- error message when method does not allow a body and body is provided.
933-- error message when method does not allow a body and body is provided.
@@ -948,7 +953,7 @@ instance HttpBody body => RequestComponent (Womb "body" body) where
948 (Y.hContentType, contentType) : old }
953 (Y.hContentType, contentType) : old }
949
954
950----------------------------------------------------------------------------
955----------------------------------------------------------------------------
951−-- Request — Optional parameters
956+-- Request—Optional parameters
952
957
953-- $optional-parameters
958-- $optional-parameters
954--
959--
@@ -966,9 +971,10 @@ data Option (scheme :: Scheme) =
966 Option (Endo (Y.QueryText, L.Request)) (Maybe (L.Request -> IO L.Request))
971 Option (Endo (Y.QueryText, L.Request)) (Maybe (L.Request -> IO L.Request))
967 -- NOTE 'QueryText' is just [(Text, Maybe Text)], we keep it along with
972 -- NOTE 'QueryText' is just [(Text, Maybe Text)], we keep it along with
968 -- Request to avoid appending to existing query string in request every
973 -- Request to avoid appending to existing query string in request every
969− -- time new parameter is added. Additional Maybe (Endo Request) is a
974+ -- time new parameter is added. Additional Maybe (L.Request -> IO
970− -- finalizer that will be applied after all other transformations. This is
975+ -- L.Request) is a finalizer that will be applied after all other
971− -- for authentication methods that sign requests based on data in Request.
976+ -- transformations. This is for authentication methods that sign requests
977+ -- based on data in Request.
972
978
973instance Semigroup (Option scheme) where
979instance Semigroup (Option scheme) where
974 Option er0 mr0 <> Option er1 mr1 = Option
980 Option er0 mr0 <> Option er1 mr1 = Option
@@ -979,7 +985,7 @@ instance Monoid (Option scheme) where
979 mappend = (<>)
985 mappend = (<>)
980
986
981-- | A helper to create an 'Option' that modifies only collection of query
987-- | A helper to create an 'Option' that modifies only collection of query
982−-- parameters. This helper is not a part of public API.
988+-- parameters. This helper is not a part of the public API.
983
989
984withQueryParams :: (Y.QueryText -> Y.QueryText) -> Option scheme
990withQueryParams :: (Y.QueryText -> Y.QueryText) -> Option scheme
985withQueryParams f = Option (Endo (first f)) Nothing
991withQueryParams f = Option (Endo (first f)) Nothing
@@ -991,7 +997,7 @@ withRequest :: (L.Request -> L.Request) -> Option scheme
991withRequest f = Option (Endo (second f)) Nothing
997withRequest f = Option (Endo (second f)) Nothing
992
998
993-- | A helper to create an 'Option' that adds a finalizer (request
999-- | A helper to create an 'Option' that adds a finalizer (request
994−-- endomorphism that is run after all other modifications).
1000+-- transformation that is applied after all other modifications).
995
1001
996asFinalizer :: (L.Request -> IO L.Request) -> Option scheme
1002asFinalizer :: (L.Request -> IO L.Request) -> Option scheme
997asFinalizer = Option mempty . pure
1003asFinalizer = Option mempty . pure
@@ -1002,20 +1008,20 @@ instance RequestComponent (Option scheme) where
1002 query = Y.renderQuery True (Y.queryTextToQuery qparams)
1008 query = Y.renderQuery True (Y.queryTextToQuery qparams)
1003 in x' { L.queryString = query }
1009 in x' { L.queryString = query }
1004
1010
1005−-- | Finalize given 'L.Request' by applying a finalizer from given 'Option'
1011+-- | Finalize given 'L.Request' by applying a finalizer from the given
1006−-- (if it has any).
1012+-- 'Option' (if it has any).
1007
1013
1008finalizeRequest :: MonadIO m => Option scheme -> L.Request -> m L.Request
1014finalizeRequest :: MonadIO m => Option scheme -> L.Request -> m L.Request
1009finalizeRequest (Option _ mfinalizer) = liftIO . fromMaybe pure mfinalizer
1015finalizeRequest (Option _ mfinalizer) = liftIO . fromMaybe pure mfinalizer
1010
1016
1011----------------------------------------------------------------------------
1017----------------------------------------------------------------------------
1012−-- Request — Optional parameters — Query Parameters
1018+-- Request—Optional parameters—Query Parameters
1013
1019
1014-- $query-parameters
1020-- $query-parameters
1015--
1021--
1016-- This section describes a polymorphic interface that can be used to
1022-- This section describes a polymorphic interface that can be used to
1017−-- construct query parameters (of type 'Option') and form URL-encoded bodies
1023+-- construct query parameters (of the type 'Option') and form URL-encoded
1018−-- (of type 'FormUrlEncodedParam').
1024+-- bodies (of the type 'FormUrlEncodedParam').
1019
1025
1020-- | This operator builds a query parameter that will be included in URL of
1026-- | This operator builds a query parameter that will be included in URL of
1021-- your request after question sign @?@. This is the same syntax you use
1027-- your request after question sign @?@. This is the same syntax you use
@@ -1026,22 +1032,23 @@ finalizeRequest (Option _ mfinalizer) = liftIO . fromMaybe pure mfinalizer
1026-- > name =: value = queryParam name (pure value)
1032-- > name =: value = queryParam name (pure value)
1027
1033
1028infix 7 =:
1034infix 7 =:
1029−(=:) :: (QueryParam param, ToHttpApiData a) => T.Text -> a -> param
1035+(=:) :: (QueryParam param, ToHttpApiData a) => Text -> a -> param
1030name =: value = queryParam name (pure value)
1036name =: value = queryParam name (pure value)
1031
1037
1032-- | Construct a flag, that is, valueless query parameter. For example, in
1038-- | Construct a flag, that is, valueless query parameter. For example, in
1033−-- the following URL @a@ is a flag, @b@ is a query parameter with a value:
1039+-- the following URL @a@ is a flag, while @b@ is a query parameter with a
1040+-- value:
1034--
1041--
1035-- > https://httpbin.org/foo/bar?a&b=10
1042-- > https://httpbin.org/foo/bar?a&b=10
1036--
1043--
1037-- This operator is defined in terms of 'queryParam':
1044-- This operator is defined in terms of 'queryParam':
1038--
1045--
1039−-- > queryFlag name = queryParam name Nothing
1046+-- > queryFlag name = queryParam name (Nothing :: Maybe ())
1040
1047
1041−queryFlag :: QueryParam param => T.Text -> param
1048+queryFlag :: QueryParam param => Text -> param
1042queryFlag name = queryParam name (Nothing :: Maybe ())
1049queryFlag name = queryParam name (Nothing :: Maybe ())
1043
1050
1044−-- | A type class for query-parameter-like things. The reason to have
1051+-- | A type class for query-parameter-like things. The reason to have an
1045-- overloaded 'queryParam' is to be able to use it as an 'Option' and as a
1052-- overloaded 'queryParam' is to be able to use it as an 'Option' and as a
1046-- 'FormUrlEncodedParam' when constructing form URL encoded request bodies.
1053-- 'FormUrlEncodedParam' when constructing form URL encoded request bodies.
1047-- Having the same syntax for these cases seems natural and user-friendly.
1054-- Having the same syntax for these cases seems natural and user-friendly.
@@ -1053,14 +1060,14 @@ class QueryParam param where
1053 -- way). It's recommended to use @('=:')@ and 'queryFlag' instead of this
1060 -- way). It's recommended to use @('=:')@ and 'queryFlag' instead of this
1054 -- method, because they are easier to read.
1061 -- method, because they are easier to read.
1055
1062
1056− queryParam :: ToHttpApiData a => T.Text -> Maybe a -> param
1063+ queryParam :: ToHttpApiData a => Text -> Maybe a -> param
1057
1064
1058instance QueryParam (Option scheme) where
1065instance QueryParam (Option scheme) where
1059 queryParam name mvalue =
1066 queryParam name mvalue =
1060 withQueryParams ((:) (name, toQueryParam <$> mvalue))
1067 withQueryParams ((:) (name, toQueryParam <$> mvalue))
1061
1068
1062----------------------------------------------------------------------------
1069----------------------------------------------------------------------------
1063−-- Request — Optional parameters — Headers
1070+-- Request—Optional parameters—Headers
1064
1071
1065-- | Create an 'Option' that adds a header. Note that if you 'mappend' two
1072-- | Create an 'Option' that adds a header. Note that if you 'mappend' two
1066-- headers with the same names the leftmost header will win. This means, in
1073-- headers with the same names the leftmost header will win. This means, in
@@ -1081,11 +1088,11 @@ attachHeader name value x =
1081 x { L.requestHeaders = (CI.mk name, value) : L.requestHeaders x }
1088 x { L.requestHeaders = (CI.mk name, value) : L.requestHeaders x }
1082
1089
1083----------------------------------------------------------------------------
1090----------------------------------------------------------------------------
1084−-- Request — Optional parameters — Cookies
1091+-- Request—Optional parameters—Cookies
1085
1092
1086-- $cookies
1093-- $cookies
1087--
1094--
1088−-- Support for cookies is quite minimalistic at the moment, its' possible to
1095+-- Support for cookies is quite minimalistic at the moment. It's possible to
1089-- specify which cookies to send using 'cookieJar' and inspect 'L.Response'
1096-- specify which cookies to send using 'cookieJar' and inspect 'L.Response'
1090-- to extract 'L.CookieJar' from it (see 'responseCookieJar').
1097-- to extract 'L.CookieJar' from it (see 'responseCookieJar').
1091
1098
@@ -1097,7 +1104,7 @@ cookieJar jar = withRequest $ \x ->
1097 x { L.cookieJar = Just jar }
1104 x { L.cookieJar = Just jar }
1098
1105
1099----------------------------------------------------------------------------
1106----------------------------------------------------------------------------
1100−-- Request — Optional parameters — Authentication
1107+-- Request—Optional parameters—Authentication
1101
1108
1102-- $authentication
1109-- $authentication
1103--
1110--
@@ -1106,7 +1113,8 @@ cookieJar jar = withRequest $ \x ->
1106-- to manual construction of headers because it ensures that you only use
1113-- to manual construction of headers because it ensures that you only use
1107-- one authentication method at a time (they overwrite each other) and
1114-- one authentication method at a time (they overwrite each other) and
1108-- provides additional type safety that prevents leaking of credentials in
1115-- provides additional type safety that prevents leaking of credentials in
1109−-- cases when authentication relies on TLS for encrypting sensitive data.
1116+-- the cases when authentication relies on HTTPS for encrypting sensitive
1117+-- data.
1110
1118
1111-- | The 'Option' adds basic authentication.
1119-- | The 'Option' adds basic authentication.
1112--
1120--
@@ -1169,7 +1177,7 @@ oAuth2Token token = asFinalizer
1169 (pure . attachHeader "Authorization" ("token " <> token))
1177 (pure . attachHeader "Authorization" ("token " <> token))
1170
1178
1171----------------------------------------------------------------------------
1179----------------------------------------------------------------------------
1172−-- Request — Optional parameters — Other
1180+-- Request—Optional parameters—Other
1173
1181
1174-- | Specify the port to connect to explicitly. Normally, 'Url' you use
1182-- | Specify the port to connect to explicitly. Normally, 'Url' you use
1175-- determines the default port: @80@ for HTTP and @443@ for HTTPS. This
1183-- determines the default port: @80@ for HTTP and @443@ for HTTPS. This
@@ -1196,8 +1204,8 @@ decompress
1196decompress f = withRequest $ \x ->
1204decompress f = withRequest $ \x ->
1197 x { L.decompress = f }
1205 x { L.decompress = f }
1198
1206
1199−-- | Specify number of microseconds to wait for response. The default value
1207+-- | Specify the number of microseconds to wait for response. The default
1200−-- is 30 seconds.
1208+-- value is 30 seconds.
1201
1209
1202responseTimeout
1210responseTimeout
1203 :: Int -- ^ Number of microseconds to wait
1211 :: Int -- ^ Number of microseconds to wait
@@ -1205,7 +1213,7 @@ responseTimeout
1205responseTimeout n = withRequest $ \x ->
1213responseTimeout n = withRequest $ \x ->
1206 x { L.responseTimeout = LI.ResponseTimeoutMicro n }
1214 x { L.responseTimeout = LI.ResponseTimeoutMicro n }
1207
1215
1208−-- | HTTP version to send to server, the default is HTTP 1.1.
1216+-- | HTTP version to send to the server, the default is HTTP 1.1.
1209
1217
1210httpVersion
1218httpVersion
1211 :: Int -- ^ Major version number
1219 :: Int -- ^ Major version number
@@ -1236,7 +1244,7 @@ ignoreResponse = Proxy
1236-- | Make a request and interpret body of response as JSON. The
1244-- | Make a request and interpret body of response as JSON. The
1237-- 'handleHttpException' method of 'MonadHttp' instance corresponding to
1245-- 'handleHttpException' method of 'MonadHttp' instance corresponding to
1238-- monad in which you use 'req' will determine what to do in the case when
1246-- monad in which you use 'req' will determine what to do in the case when
1239−-- parsing fails ('JsonHttpException' constructor will be used).
1247+-- parsing fails (the 'JsonHttpException' constructor will be used).
1240
1248
1241newtype JsonResponse a = JsonResponse (L.Response a)
1249newtype JsonResponse a = JsonResponse (L.Response a)
1242
1250
@@ -1290,8 +1298,8 @@ instance HttpResponse LbsResponse where
1290lbsResponse :: Proxy LbsResponse
1298lbsResponse :: Proxy LbsResponse
1291lbsResponse = Proxy
1299lbsResponse = Proxy
1292
1300
1293−-- | This interpretation does not result in any call at all, but you can use
1301+-- | This interpretation does not result in any request at all, but you can
1294−-- the 'responseRequest' function to extract 'L.Request' that 'req' has
1302+-- use the 'responseRequest' function to extract 'L.Request' that 'req' has
1295-- prepared. This is useful primarily for testing.
1303-- prepared. This is useful primarily for testing.
1296--
1304--
1297-- Note that when you use this interpretation inspecting response will
1305-- Note that when you use this interpretation inspecting response will
@@ -1314,7 +1322,7 @@ returnRequest = Proxy
1314----------------------------------------------------------------------------
1322----------------------------------------------------------------------------
1315-- Inspecting a response
1323-- Inspecting a response
1316
1324
1317−-- | Get response body.
1325+-- | Get the response body.
1318
1326
1319responseBody
1327responseBody
1320 :: HttpResponse response
1328 :: HttpResponse response
@@ -1322,7 +1330,7 @@ responseBody
1322 -> HttpResponseBody response
1330 -> HttpResponseBody response
1323responseBody = L.responseBody . toVanillaResponse
1331responseBody = L.responseBody . toVanillaResponse
1324
1332
1325−-- | Get response status code.
1333+-- | Get the response status code.
1326
1334
1327responseStatusCode
1335responseStatusCode
1328 :: HttpResponse response
1336 :: HttpResponse response
@@ -1331,7 +1339,7 @@ responseStatusCode
1331responseStatusCode =
1339responseStatusCode =
1332 Y.statusCode . L.responseStatus . toVanillaResponse
1340 Y.statusCode . L.responseStatus . toVanillaResponse
1333
1341
1334−-- | Get response status message.
1342+-- | Get the response status message.
1335
1343
1336responseStatusMessage
1344responseStatusMessage
1337 :: HttpResponse response
1345 :: HttpResponse response
@@ -1340,7 +1348,7 @@ responseStatusMessage
1340responseStatusMessage =
1348responseStatusMessage =
1341 Y.statusMessage . L.responseStatus . toVanillaResponse
1349 Y.statusMessage . L.responseStatus . toVanillaResponse
1342
1350
1343−-- | Look a particular header from a response.
1351+-- | Lookup a particular header from a response.
1344
1352
1345responseHeader
1353responseHeader
1346 :: HttpResponse response
1354 :: HttpResponse response
@@ -1350,7 +1358,7 @@ responseHeader
1350responseHeader r h =
1358responseHeader r h =
1351 (lookup (CI.mk h) . L.responseHeaders . toVanillaResponse) r
1359 (lookup (CI.mk h) . L.responseHeaders . toVanillaResponse) r
1352
1360
1353−-- | Get response 'L.CookieJar'.
1361+-- | Get the response 'L.CookieJar'.
1354
1362
1355responseCookieJar
1363responseCookieJar
1356 :: HttpResponse response
1364 :: HttpResponse response
@@ -1364,7 +1372,7 @@ responseRequest :: ReturnRequest -> L.Request
1364responseRequest (ReturnRequest request) = request
1372responseRequest (ReturnRequest request) = request
1365
1373
1366----------------------------------------------------------------------------
1374----------------------------------------------------------------------------
1367−-- Response — defining your own interpretation
1375+-- Response—Defining your own interpretation
1368
1376
1369-- $new-response-interpretation
1377-- $new-response-interpretation
1370--
1378--
@@ -1376,17 +1384,17 @@ responseRequest (ReturnRequest request) = request
1376
1384
1377class HttpResponse response where
1385class HttpResponse response where
1378
1386
1379− -- | The associated type is the type of body that can be extracted from a
1387+ -- | The associated type is the type of body that can be extracted from an
1380 -- instance of 'HttpResponse'.
1388 -- instance of 'HttpResponse'.
1381
1389
1382 type HttpResponseBody response :: *
1390 type HttpResponseBody response :: *
1383
1391
1384− -- | The method describes how to get underlying 'L.Response' record.
1392+ -- | The method describes how to get the underlying 'L.Response' record.
1385
1393
1386 toVanillaResponse :: response -> L.Response (HttpResponseBody response)
1394 toVanillaResponse :: response -> L.Response (HttpResponseBody response)
1387
1395
1388 -- | This method describes how to make an HTTP request given 'L.Request'
1396 -- | This method describes how to make an HTTP request given 'L.Request'
1389− -- (prepared by the rest of the library) and 'L.Manager'.
1397+ -- (prepared by the library) and 'L.Manager'.
1390
1398
1391 getHttpResponse :: L.Request -> L.Manager -> IO response
1399 getHttpResponse :: L.Request -> L.Manager -> IO response
1392
1400
@@ -1439,11 +1447,11 @@ data CanHaveBody
1439 = CanHaveBody -- ^ Indeed can have a body
1447 = CanHaveBody -- ^ Indeed can have a body
1440 | NoBody -- ^ Should not have a body
1448 | NoBody -- ^ Should not have a body
1441
1449
1442−-- | A type-level tag that specifies URL scheme used (and thus if TLS is
1450+-- | A type-level tag that specifies URL scheme used (and thus if HTTPS is
1443-- enabled). This is used to force TLS requirement for some authentication
1451-- enabled). This is used to force TLS requirement for some authentication
1444-- 'Option's.
1452-- 'Option's.
1445
1453
1446data Scheme
1454data Scheme
1447− = Http -- ^ HTTP, no TLS
1455+ = Http -- ^ HTTP
1448 | Https -- ^ HTTPS
1456 | Https -- ^ HTTPS
1449 deriving (Eq, Ord, Show, Data, Typeable, Generic)
1457 deriving (Eq, Ord, Show, Data, Typeable, Generic)
README.md+43−44
@@ -60,13 +60,13 @@ manager with different settings, but it requires a bit more typing.
60classes of errors. For example, we have correct-by-construction URLs, it's
60classes of errors. For example, we have correct-by-construction URLs, it's
61guaranteed that the user does not send the request body when using methods
61guaranteed that the user does not send the request body when using methods
62like GET or OPTIONS, and the amount of implicit assumptions is minimized by
62like GET or OPTIONS, and the amount of implicit assumptions is minimized by
63−making the user specify his/her intentions in and explicit form (for
63+making the user specify his/her intentions in an explicit form (for example,
64−example, it's not possible to avoid specifying the body or method of a
64+it's not possible to avoid specifying the body or method of a request).
65−request). Authentication methods that assume TLS force the user to use TLS
65+Authentication methods that assume HTTPS force the user to use HTTPS at the
66−at the type level. The library also carefully hides underlying types from
66+type level. The library also carefully hides underlying types from the
67−the lower-level `http-client` package because those types are not safe
67+lower-level `http-client` package because those types are not safe enough
68−enough (for example `Request` is an instance of `IsString` and, if it's
68+(for example `Request` is an instance of `IsString` and, if it's malformed,
69−malformed, it will blow up at run-time).
69+it will blow up at run-time).
70
70
71“Expandable” refers to the ability to create new components for dealing with
71“Expandable” refers to the ability to create new components for dealing with
72HTTP without having to resort to ugly hacking. For example, it's possible to
72HTTP without having to resort to ugly hacking. For example, it's possible to
@@ -88,18 +88,18 @@ the library cuts boilerplate down considerably, and helps you write concise,
88easy to read, and maintainable code.
88easy to read, and maintainable code.
89
89
90The library uses the following mature packages under the hood to guarantee
90The library uses the following mature packages under the hood to guarantee
91−you the best experience that doesn't have any bugs or other funny business:
91+you the best experience:
92
92
93−* [`http-client`](https://hackage.haskell.org/package/http-client) — low
93+* [`http-client`](https://hackage.haskell.org/package/http-client)—low level
94− level HTTP client used everywhere in Haskell.
94+ HTTP client used everywhere in Haskell.
95
95
96−* [`http-client-tls`](https://hackage.haskell.org/package/http-client-tls) —
96+* [`http-client-tls`](https://hackage.haskell.org/package/http-client-tls)—TLS
97− TLS (HTTPS) support for `http-client`.
97+ (HTTPS) support for `http-client`.
98
98
99It's important to note that since we leverage well-known libraries that the
99It's important to note that since we leverage well-known libraries that the
100whole Haskell ecosystem uses, there is no risk in using Req. The machinery
100whole Haskell ecosystem uses, there is no risk in using Req. The machinery
101−for performing requests is the same as `http-conduit` and Wreq. The only
101+for performing requests is the same as with `http-conduit` and Wreq. The
102−difference is the API.
102+only difference is the API.
103
103
104## Motivation and Req vs other libraries
104## Motivation and Req vs other libraries
105
105
@@ -117,7 +117,7 @@ have no issues with the libraries except that they are too low-level for my
117taste. Indeed, even the docs say that they are low-level and “intended as a
117taste. Indeed, even the docs say that they are low-level and “intended as a
118base layer for more user-friendly packages”. This is exactly how I use them
118base layer for more user-friendly packages”. This is exactly how I use them
119in Req, as base level. Req is nothing but a different API to `http-client`,
119in Req, as base level. Req is nothing but a different API to `http-client`,
120−so it only works because of hard work put into `http-client`.
120+so it only works because of the hard work put into `http-client`.
121
121
122`http-conduit` definitely has its place. For one thing it allows you to
122`http-conduit` definitely has its place. For one thing it allows you to
123stream request and response bodies in constant memory, what other library
123stream request and response bodies in constant memory, what other library
@@ -125,19 +125,19 @@ allows you to do that? On the other hand if you take a look at
125`Network.HTTP.Simple`, then although it's said that it's a “higher level
125`Network.HTTP.Simple`, then although it's said that it's a “higher level
126API”, it's mostly the same as vanilla `http-client` in spirit/approach and
126API”, it's mostly the same as vanilla `http-client` in spirit/approach and
127just adds `conduit`-powered functions to perform requests and allows to use
127just adds `conduit`-powered functions to perform requests and allows to use
128−global implicit `Manager` (super-cool idea, BTW, Req does the same). If I
128+global implicit `Manager` (Req does the same). If I tried to frame what
129−tried to frame what exactly I don't like about `http-conduit` in words, then
129+exactly I don't like about `http-conduit` in words, then it would be “the
130−it would be “the way requests are constructed”. You set, set, set instead of
130+way requests are constructed”. You set, set, set instead of *being forced*
131−*being forced* to declare necessary bits and *being allowed* to declare
131+to declare necessary bits and *being allowed* to declare optional bits in a
132−optional bits in a way that their combination is certainly valid. And you
132+way that their combination is certainly valid. And you parse request from a
133−parse request from a string without the protection of TH that otherwise
133+string without the protection of TH that otherwise saves the day as in
134−saves the day as in Yesod.
134+Yesod.
135
135
136Then there is Wreq.
136Then there is Wreq.
137`wreq`
137`wreq`
138[doesn't see much development lately](https://github.com/bos/wreq/issues/93).
138[doesn't see much development lately](https://github.com/bos/wreq/issues/93).
139−`wreq` is by itself a weird library, IMO. You have functions per method —
139+`wreq` is by itself a weird library, IMO. You have functions per method—not
140−not very good, as there may be new methods, like PATCH which is not new but
140+very good, as there may be new methods, like PATCH which is not new but
141still missing (well you have `customMethod`, but what is the point of having
141still missing (well you have `customMethod`, but what is the point of having
142per-method functions if you have a more general way to use any method? you
142per-method functions if you have a more general way to use any method? you
143should be able to just insert methods in the “argument slot” of
143should be able to just insert methods in the “argument slot” of
@@ -150,14 +150,12 @@ take the gift of automatic connection re-use `Manager` from `http-client`
150provides, he invents the whole new thing of “sessions”. Only inside a
150provides, he invents the whole new thing of “sessions”. Only inside a
151session your connections will be shared and re-used. However with the
151session your connections will be shared and re-used. However with the
152session stuff you have yet another set of per-method functions like `get`
152session stuff you have yet another set of per-method functions like `get`
153−and `getWith` — these are different ones, to be used with sessions! Now if
153+and `getWith`—these are different ones, to be used with sessions! Now if you
154−you have multi-threaded app, here is a surprise for you: you can't share
154+have a multi-threaded app, here is a surprise for you: you can't share
155connections between threads as connections are shared only inside
155connections between threads as connections are shared only inside
156`withSession` friend and “session will no longer be valid after that
156`withSession` friend and “session will no longer be valid after that
157−function returns”. Disclaimer: I don't use Wreq, see below. If something in
158−this paragraph is not correct, please let me know and I'll remove it. Also
159−there are valid uses for sessions, but the point is that they are too
157+function returns”. There are valid uses for sessions, but the point is that
160−inconvenient for common tasks.
158+they are just too inconvenient for common tasks.
161
159
162It's funny that one client I worked for had to have his own little wrapper
160It's funny that one client I worked for had to have his own little wrapper
163around `http-client` just because he could not possibly use `wreq` and
161around `http-client` just because he could not possibly use `wreq` and
@@ -172,26 +170,27 @@ just one of them, good luck passing lots of `Nothing`s.
172
170
173## Unsolved problems
171## Unsolved problems
174
172
175−AWS request signing is problematic because request body can be in form of
173+AWS request signing is problematic because request body can be in the form
176−action to execute (and all that “popper” stuff for streaming), not just
174+of an action to execute (and all that “popper” stuff for streaming), not
177−`ByteString` and so getting its digest (hash) is not trivial without running
175+just a `ByteString` and so getting its digest (hash) is not trivial without
178−the action and consuming body in its entirety before the request in made. In
176+running the action and consuming body in its entirety before the request in
179−Wreq the author chose to just use `error` when body is not a (strict or
177+made. In Wreq the author chose to just use `error` when body is not a
180−lazy) `ByteString`. Maybe it's OK for Wreq, but I don't consider this proper
178+(strict or lazy) `ByteString`. Maybe it's OK for Wreq, but I don't consider
181−solution for Req as we support full variety of body options. For example
179+this a proper solution for Req as we support full variety of body options.
182−what if I want to upload 1 Gb file to S3? I want to stream it in constant
180+For example what if I want to upload 1 Gb file to S3? I want to stream it in
183−memory but at the same time I need to calculate its hash before I start
181+constant memory but at the same time I need to calculate its hash before I
184−streaming. One solution to the problem seems to be in taking the hash
182+start streaming. One solution to the problem seems to be in taking the hash
185−explicitly (as an argument of hypothetical `awsAuth`) and making it
183+explicitly (as an argument of the hypothetical `awsAuth`) and making it a
186−responsibility of library user to calculate the hash correctly. I don't like
184+responsibility of the user to calculate the hash correctly. I don't like
187this because it's not user-friendly. So the question stays open, for now
185this because it's not user-friendly. So the question stays open, for now
188−there is no AWS signing functionality provided out-of-the-box.
186+there is no AWS signing functionality provided out-of-the-box. The best
187+solution for talking to AWS is the `amazonka` package so far.
189
188
190## Related packages
189## Related packages
191
190
192The following packages are designed to be used with Req:
191The following packages are designed to be used with Req:
193
192
194−* [`req-conduit`](https://hackage.haskell.org/package/req-conduit) — support
193+* [`req-conduit`](https://hackage.haskell.org/package/req-conduit)—support
195 for streaming request and response bodies in constant memory.
194 for streaming request and response bodies in constant memory.
196
195
197If you happen to have written a package that adds new features to Req,
196If you happen to have written a package that adds new features to Req,