on master help sign in
Improve the writing
commit727a711a01dea7c22a14fc7c5facaeeb613c6a6f authorMark Karpov <markkarpov92@gmail.com> dateFri 23 Apr 2021, 11:03 (5 years ago) parent574afc2
5 files changed+110−235
Network/HTTP/Req.hs+72−98 README.md+27−121 httpbin-tests/Network/HTTP/ReqSpec.hs+4−5 pure-tests/Network/HTTP/ReqSpec.hs+2−2 req.cabal+5−9
Network/HTTP/Req.hs+72−98
@@ -30,61 +30,40 @@
3030--
3131-- The documentation below is structured in such a way that the most
3232-- important information is presented first: you learn how to do HTTP
33−-- requests, how to embed them in any monad you have, and then it gives you
33+-- requests, how to embed them in the monad you have, and then it gives you
3434-- details about less-common things you may want to know about. The
3535-- documentation is written with sufficient coverage of details and
3636-- examples, and it's designed to be a complete tutorial on its own.
3737--
38−-- /(A modest intro goes here, click on 'req' to start making requests.)/
39−--
4038-- === About the library
4139--
42−-- Req is an easy-to-use, type-safe, expandable, high-level HTTP client
43−-- library that just works without any fooling around.
44−--
45−-- What does the phrase “easy-to-use” mean? It means that the library is
46−-- designed to be beginner-friendly so it's simple to add to your monad
47−-- stack, intuitive to work with, well-documented, and does not get in your
48−-- way. Doing HTTP requests is a common task and Haskell library for this
49−-- should be very approachable and clear to beginners, thus certain
50−-- compromises were made. For example, one cannot currently modify
51−-- 'L.ManagerSettings' of the default manager because the library always
52−-- uses the same implicit global manager for simplicity and maximal
53−-- connection sharing. There is a way to use your own manager with different
54−-- settings, but it requires a bit more typing.
55−--
56−-- “Type-safe” means that the library is protective and eliminates certain
57−-- classes of errors. For example, we have correct-by-construction 'Url's,
58−-- it's guaranteed that the user does not send the request body when using
59−-- methods like 'GET' or 'OPTIONS', and the amount of implicit assumptions
60−-- is minimized by making the user specify his\/her intentions in an
61−-- explicit form (for example, it's not possible to avoid specifying the
62−-- body or method of request). Authentication methods that assume HTTPS
63−-- force the user to use HTTPS at the type level. The library also carefully
64−-- hides underlying types from the lower-level @http-client@ package because
65−-- those types are not safe enough (for example 'L.Request' is an instance
66−-- of 'Data.String.IsString' and, if it's malformed, it will blow up at
67−-- run-time).
68−--
69−-- “Expandable” refers to the ability of the library to be expanded without
70−-- having to resort to ugly hacking. For example, it's possible to define
71−-- your own HTTP methods, create new ways to construct the body of a
72−-- request, create new authorization options, perform a request in a
73−-- different way, and create your own methods to parse and represent a
74−-- response. As the user extends the library to satisfy his\/her special
75−-- needs, the new solutions will work just like the built-ins. However, all
76−-- of the common cases are also covered by the library out-of-the-box.
77−--
78−-- “High-level” means that there are less details to worry about. The
79−-- library is a result of my experiences as a Haskell consultant. Working
80−-- for several clients, who had very different projects, showed me that the
81−-- library should adapt easily to any particular style of writing Haskell
82−-- applications. For example, some people prefer throwing exceptions, while
83−-- others are concerned with purity. Just define 'handleHttpException'
84−-- accordingly when making your monad instance of 'MonadHttp' and it will
85−-- play together seamlessly. Finally, the library cuts down boilerplate
86−-- considerably, and helps you write concise, easy to read, and maintainable
87−-- code.
40+-- Req is an HTTP client library that attempts to be easy-to-use, type-safe,
41+-- and expandable.
42+--
43+-- “Easy-to-use” means that the library is designed to be beginner-friendly
44+-- so it's simple to add to your monad stack, intuitive to work with,
45+-- well-documented, and does not get in your way. Doing HTTP requests is a
46+-- common task and a Haskell library for this should be approachable and
47+-- clear to beginners, thus certain compromises were made. For example, one
48+-- cannot currently modify 'L.ManagerSettings' of the default manager
49+-- because the library always uses the same implicit global manager for
50+-- simplicity and maximal connection sharing. There is a way to use your own
51+-- manager with different settings, but it requires more typing.
52+--
53+-- “Type-safe” means that the library tries to eliminate certain classes of
54+-- errors. For example, we have correct-by-construction URLs; it is
55+-- guaranteed that the user does not send the request body when using
56+-- methods like GET or OPTIONS, and the amount of implicit assumptions is
57+-- minimized by making the user specify their intentions in an explicit
58+-- form. For example, it's not possible to avoid specifying the body or the
59+-- method of a request. Authentication methods that assume HTTPS force the
60+-- user to use HTTPS at the type level.
61+--
62+-- “Expandable” refers to the ability to create new components without
63+-- having to resort to hacking. For example, it's possible to define your
64+-- own HTTP methods, create new ways to construct the body of a request,
65+-- create new authorization options, perform a request in a different way,
66+-- and create your own methods to parse a response.
8867--
8968-- === Using with other libraries
9069--
@@ -303,7 +282,7 @@ import Web.HttpApiData (ToHttpApiData (..))
303282--
304283-- @body@ is a body option such as 'NoReqBody' or 'ReqBodyJson'. The
305284-- tutorial has a section about HTTP bodies, but usage is very
306−-- straightforward and should be clear from the examples below.
285+-- straightforward and should be clear from the examples.
307286--
308287-- @response@ is a type hint how to make and interpret response of an HTTP
309288-- request. Out-of-the-box it can be the following:
@@ -588,9 +567,9 @@ req' method url body options m = do
588567 nubHeaders
589568 <> getRequestMod options
590569 <> getRequestMod config
591− <> getRequestMod (Womb body :: Womb "body" body)
570+ <> getRequestMod (Tagged body :: Tagged "body" body)
592571 <> getRequestMod url
593− <> getRequestMod (Womb method :: Womb "method" method)
572+ <> getRequestMod (Tagged method :: Tagged "method" method)
594573 request <- finalizeRequest options request'
595574 withReqManager (m request)
596575
@@ -600,10 +579,10 @@ req' method url body options m = do
600579withReqManager :: MonadIO m => (L.Manager -> m a) -> m a
601580withReqManager m = liftIO (readIORef globalManager) >>= m
602581
603−-- | Global 'L.Manager' that 'req' uses. Here we just go with the default
604−-- settings, so users don't need to deal with this manager stuff at all, but
605−-- when we create a request, instance 'HttpConfig' can affect the default
606−-- settings via 'getHttpConfig'.
582+-- | The global 'L.Manager' that 'req' uses. Here we just go with the
583+-- default settings, so users don't need to deal with this manager stuff at
584+-- all, but when we create a request, instance 'HttpConfig' can affect the
585+-- default settings via 'getHttpConfig'.
607586--
608587-- A note about safety, in case 'unsafePerformIO' looks suspicious to you.
609588-- The value of 'globalManager' is named and lives on top level. This means
@@ -634,8 +613,8 @@ globalManager = unsafePerformIO $ do
634613-- When writing a library, keep your API polymorphic in terms of
635614-- 'MonadHttp', only define instance of 'MonadHttp' in final application.
636615-- Another option is to use a @newtype@-wrapped monad stack and define
637−-- 'MonadHttp' for it. As of version /0.4.0/, the 'Req' monad that follows
638−-- this strategy is provided out-of-the-box (see below).
616+-- 'MonadHttp' for it. As of the version /0.4.0/, the 'Req' monad that
617+-- follows this strategy is provided out-of-the-box (see below).
639618
640619-- | A type class for monads that support performing HTTP requests.
641620-- Typically, you only need to define the 'handleHttpException' method
@@ -648,17 +627,16 @@ class MonadIO m => MonadHttp m where
648627 -- 'Control.Monad.Except.throwError'.
649628 handleHttpException :: HttpException -> m a
650629
651− -- | Return 'HttpConfig' to be used when performing HTTP requests. Default
652− -- implementation returns its 'def' value, which is described in the
653− -- documentation for the type. Common usage pattern with manually defined
654− -- 'getHttpConfig' is to return some hard-coded value, or a value
630+ -- | Return the 'HttpConfig' to be used when performing HTTP requests.
631+ -- Default implementation returns its 'def' value, which is described in
632+ -- the documentation for the type. Common usage pattern with manually
633+ -- defined 'getHttpConfig' is to return some hard-coded value, or a value
655634 -- extracted from 'Control.Monad.Reader.MonadReader' if a more flexible
656635 -- approach to configuration is desirable.
657636 getHttpConfig :: m HttpConfig
658637 getHttpConfig = return defaultHttpConfig
659638
660−-- | 'HttpConfig' contains general and default settings to be used when
661−-- making HTTP requests.
639+-- | 'HttpConfig' contains settings to be used when making HTTP requests.
662640data HttpConfig = HttpConfig
663641 { -- | Proxy to use. By default values of @HTTP_PROXY@ and @HTTPS_PROXY@
664642 -- environment variables are respected, this setting overwrites them.
@@ -729,7 +707,7 @@ data HttpConfig = HttpConfig
729707 }
730708 deriving (Typeable)
731709
732−-- | Default value of 'HttpConfig'.
710+-- | The default value of 'HttpConfig'.
733711--
734712-- @since 2.0.0
735713defaultHttpConfig :: HttpConfig
@@ -773,7 +751,7 @@ instance RequestComponent HttpConfig where
773751 LI.requestManagerOverride = httpConfigAltManager
774752 }
775753
776−-- | A monad that allows to run 'req' in any 'IO'-enabled monad without
754+-- | A monad that allows us to run 'req' in any 'IO'-enabled monad without
777755-- having to define new instances.
778756--
779757-- @since 0.4.0
@@ -810,7 +788,7 @@ instance MonadHttp Req where
810788 getHttpConfig = Req ask
811789
812790-- | Run a computation in the 'Req' monad with the given 'HttpConfig'. In
813−-- case of exceptional situation an 'HttpException' will be thrown.
791+-- the case of an exceptional situation an 'HttpException' will be thrown.
814792--
815793-- @since 0.4.0
816794runReq ::
@@ -919,7 +897,7 @@ class HttpMethod a where
919897 -- | Return name of the method as a 'ByteString'.
920898 httpMethodName :: Proxy a -> ByteString
921899
922−instance HttpMethod method => RequestComponent (Womb "method" method) where
900+instance HttpMethod method => RequestComponent (Tagged "method" method) where
923901 getRequestMod _ = Endo $ \x ->
924902 x {L.method = httpMethodName (Proxy :: Proxy method)}
925903
@@ -966,7 +944,7 @@ data Url (scheme :: Scheme) = Url Scheme (NonEmpty Text)
966944type role Url nominal
967945
968946-- With template-haskell >=2.15 and text >=1.2.4 Lift can be derived, however
969−-- the derived lift forgets the type of scheme.
947+-- the derived lift forgets the type of the scheme.
970948instance Typeable scheme => TH.Lift (Url scheme) where
971949 lift url =
972950 TH.dataToExpQ (fmap liftText . cast) url `TH.sigE` case url of
@@ -989,14 +967,14 @@ http = Url Http . pure
989967https :: Text -> Url 'Https
990968https = Url Https . pure
991969
992−-- | Grow given 'Url' appending a single path segment to it. Note that the
970+-- | Grow a given 'Url' appending a single path segment to it. Note that the
993971-- path segment can be of any type that is an instance of 'ToHttpApiData'.
994972infixl 5 /~
995973
996974(/~) :: ToHttpApiData a => Url scheme -> a -> Url scheme
997975Url secure path /~ segment = Url secure (NE.cons (toUrlPiece segment) path)
998976
999−-- | Type-constrained version of @('/~')@ to remove ambiguity in the cases
977+-- | A type-constrained version of @('/~')@ to remove ambiguity in the cases
1000978-- when next URL piece is a 'Data.Text.Text' literal.
1001979infixl 5 /:
1002980
@@ -1172,10 +1150,10 @@ data NoReqBody = NoReqBody
11721150instance HttpBody NoReqBody where
11731151 getRequestBody NoReqBody = L.RequestBodyBS B.empty
11741152
1175−-- | This body option allows to use a JSON object as request body—probably
1176−-- the most popular format right now. Just wrap a data type that is an
1177−-- instance of 'ToJSON' type class and you are done: it will be converted to
1178−-- JSON and inserted as request body.
1153+-- | This body option allows us to use a JSON object as the request
1154+-- body—probably the most popular format right now. Just wrap a data type
1155+-- that is an instance of 'ToJSON' type class and you are done: it will be
1156+-- converted to JSON and inserted as request body.
11791157--
11801158-- This body option sets the @Content-Type@ header to @\"application/json;
11811159-- charset=utf-8\"@ value.
@@ -1186,7 +1164,7 @@ instance ToJSON a => HttpBody (ReqBodyJson a) where
11861164 getRequestContentType _ = pure "application/json; charset=utf-8"
11871165
11881166-- | This body option streams request body from a file. It is expected that
1189−-- the file size does not change during the streaming.
1167+-- the file size does not change during streaming.
11901168--
11911169-- Using of this body option does not set the @Content-Type@ header.
11921170newtype ReqBodyFile = ReqBodyFile FilePath
@@ -1211,12 +1189,11 @@ newtype ReqBodyLbs = ReqBodyLbs BL.ByteString
12111189instance HttpBody ReqBodyLbs where
12121190 getRequestBody (ReqBodyLbs bs) = L.RequestBodyLBS bs
12131191
1214−-- | Form URL-encoded body. This can hold a collection of parameters which
1215−-- are encoded similarly to query parameters at the end of query string,
1216−-- with the only difference that they are stored in request body. The
1217−-- similarity is reflected in the API as well, as you can use the same
1218−-- combinators you would use to add query parameters: @('=:')@ and
1219−-- 'queryFlag'.
1192+-- | URL-encoded body. This can hold a collection of parameters which are
1193+-- encoded similarly to query parameters at the end of query string, with
1194+-- the only difference that they are stored in request body. The similarity
1195+-- is reflected in the API as well, as you can use the same combinators you
1196+-- would use to add query parameters: @('=:')@ and 'queryFlag'.
12201197--
12211198-- This body option sets the @Content-Type@ header to
12221199-- @\"application/x-www-form-urlencoded\"@ value.
@@ -1302,9 +1279,6 @@ type family ProvidesBody body :: CanHaveBody where
13021279-- | This type function allows any HTTP body if method says it
13031280-- 'CanHaveBody'. When the method says it should have 'NoBody', the only
13041281-- body option to use is 'NoReqBody'.
1305−--
1306−-- __Note__: users of GHC 8.0.1 and later will see a slightly more friendly
1307−-- error message when method does not allow a body and body is provided.
13081282type family
13091283 HttpBodyAllowed
13101284 (allowsBody :: CanHaveBody)
@@ -1317,8 +1291,8 @@ type family
13171291 TypeError
13181292 ('Text "This HTTP method does not allow attaching a request body.")
13191293
1320−instance HttpBody body => RequestComponent (Womb "body" body) where
1321− getRequestMod (Womb body) = Endo $ \x ->
1294+instance HttpBody body => RequestComponent (Tagged "body" body) where
1295+ getRequestMod (Tagged body) = Endo $ \x ->
13221296 x
13231297 { L.requestBody = getRequestBody body,
13241298 L.requestHeaders =
@@ -1347,8 +1321,8 @@ data Option (scheme :: Scheme)
13471321 = Option (Endo (Y.QueryText, L.Request)) (Maybe (L.Request -> IO L.Request))
13481322
13491323-- NOTE 'QueryText' is just [(Text, Maybe Text)], we keep it along with
1350−-- Request to avoid appending to existing query string in request every
1351−-- time new parameter is added. Additional Maybe (L.Request -> IO
1324+-- Request to avoid appending to an existing query string in request every
1325+-- time new parameter is added. The additional Maybe (L.Request -> IO
13521326-- L.Request) is a finalizer that will be applied after all other
13531327-- transformations. This is for authentication methods that sign requests
13541328-- based on data in Request.
@@ -1405,7 +1379,7 @@ infix 7 =:
14051379(=:) :: (QueryParam param, ToHttpApiData a) => Text -> a -> param
14061380name =: value = queryParam name (pure value)
14071381
1408−-- | Construct a flag, that is, valueless query parameter. For example, in
1382+-- | Construct a flag, that is, a valueless query parameter. For example, in
14091383-- the following URL @\"a\"@ is a flag, while @\"b\"@ is a query parameter
14101384-- with a value:
14111385--
@@ -1595,7 +1569,7 @@ customAuth = Option mempty . pure
15951569
15961570-- | Specify the port to connect to explicitly. Normally, 'Url' you use
15971571-- determines the default port: @80@ for HTTP and @443@ for HTTPS. This
1598−-- 'Option' allows to choose an arbitrary port overwriting the defaults.
1572+-- 'Option' allows us to choose an arbitrary port overwriting the defaults.
15991573port :: Int -> Option scheme
16001574port n = withRequest $ \x ->
16011575 x {L.port = n}
@@ -1610,8 +1584,8 @@ port n = withRequest $ \x ->
16101584--
16111585-- > decompress (const True)
16121586decompress ::
1613− -- | Predicate that is given MIME type, it
1614− -- returns 'True' when content should be decompressed on the fly.
1587+ -- | Predicate that is given MIME type, it returns 'True' when content
1588+ -- should be decompressed on the fly.
16151589 (ByteString -> Bool) ->
16161590 Option scheme
16171591decompress f = withRequest $ \x ->
@@ -1713,7 +1687,7 @@ lbsResponse = Proxy
17131687----------------------------------------------------------------------------
17141688-- Helpers for response interpretations
17151689
1716−-- | Fetch beginning of response and return it together with new
1690+-- | Fetch beginning of the response and return it together with a new
17171691-- @'L.Response' 'L.BodyReader'@ that can be passed to 'getHttpResponse' and
17181692-- such.
17191693grabPreview ::
@@ -1825,9 +1799,9 @@ responseCookieJar = L.responseCookieJar . toVanillaResponse
18251799-- To create a new response interpretation you just need to make your data
18261800-- type an instance of the 'HttpResponse' type class.
18271801
1828−-- | A type class for response interpretations. It allows to describe how to
1829−-- consume response from a @'L.Response' 'L.BodyReader'@ and produce the
1830−-- final result that is to be returned to the user.
1802+-- | A type class for response interpretations. It allows us to describe how
1803+-- to consume the response from a @'L.Response' 'L.BodyReader'@ and produce
1804+-- the final result that is to be returned to the user.
18311805class HttpResponse response where
18321806 -- | The associated type is the type of body that can be extracted from an
18331807 -- instance of 'HttpResponse'.
@@ -1891,7 +1865,7 @@ class RequestComponent a where
18911865-- method@ and @'HttpBody' body => 'RequestComponent' body@ when it decides
18921866-- which instance to use (i.e. the constraints are taken into account later,
18931867-- when instance is already chosen).
1894−newtype Womb (tag :: Symbol) a = Womb a
1868+newtype Tagged (tag :: Symbol) a = Tagged a
18951869
18961870-- | Exceptions that this library throws.
18971871data HttpException
README.md+27−121
@@ -43,49 +43,33 @@ main = runReq defaultHttpConfig $ do
4343 liftIO $ print (responseBody r :: Value)
4444```
4545
46−Req is an easy-to-use, type-safe, expandable, high-level HTTP client library
47−that just works without any fooling around.
48−
49−What does the phrase “easy-to-use” mean? It means that the library is
50−designed to be beginner-friendly so it's simple to add to your monad stack,
51−intuitive to work with, well-documented, and does not get in your way. Doing
52−HTTP requests is a common task and Haskell library for this should be very
53−approachable and clear to beginners, thus certain compromises were made. For
54−example, one cannot currently modify `ManagerSettings` of the default
55−manager because the library always uses the same implicit global manager for
56−simplicity and maximal connection sharing. There is a way to use your own
57−manager with different settings, but it requires a bit more typing.
58−
59−“Type-safe” means that the library is protective and eliminates certain
60−classes of errors. For example, we have correct-by-construction URLs, it's
61−guaranteed that the user does not send the request body when using methods
62−like GET or OPTIONS, and the amount of implicit assumptions is minimized by
63−making the user specify his/her intentions in an explicit form (for example,
64−it's not possible to avoid specifying the body or method of request).
46+Req is an HTTP client library that attempts to be easy-to-use, type-safe,
47+and expandable.
48+
49+“Easy-to-use” means that the library is designed to be beginner-friendly so
50+it's simple to add to your monad stack, intuitive to work with,
51+well-documented, and does not get in your way. Doing HTTP requests is a
52+common task and a Haskell library for this should be approachable and clear
53+to beginners, thus certain compromises were made. For example, one cannot
54+currently modify `ManagerSettings` of the default manager because the
55+library always uses the same implicit global manager for simplicity and
56+maximal connection sharing. There is a way to use your own manager with
57+different settings, but it requires more typing.
58+
59+“Type-safe” means that the library tries to eliminate certain classes of
60+errors. For example, we have correct-by-construction URLs; it is guaranteed
61+that the user does not send the request body when using methods like GET or
62+OPTIONS, and the amount of implicit assumptions is minimized by making the
63+user specify their intentions in an explicit form. For example, it's not
64+possible to avoid specifying the body or the method of a request.
6565Authentication methods that assume HTTPS force the user to use HTTPS at the
66−type level. The library also carefully hides underlying types from the
67−lower-level `http-client` package because those types are not safe enough
68−(for example `Request` is an instance of `IsString` and, if it's malformed,
69−it will blow up at run-time).
70−
71−“Expandable” refers to the ability to create new components for dealing with
72−HTTP without having to resort to ugly hacking. For example, it's possible to
73−define your own HTTP methods, create new ways to construct the body of a
74−request, create new authorization options, perform a request in a different
75−way, and create your own methods to parse and represent a response. As the
76−user extends the library to satisfy his/her special needs, the new solutions
77−will work just like the built-ins. However, all of the common cases are also
78−covered by the library out-of-the-box.
79−
80−“High-level” means that there are less details to worry about. The library
81−is a result of my experiences as a Haskell consultant. Working for several
82−clients, who had very different projects, showed me that the library should
83−adapt easily to any particular style of writing Haskell applications. For
84−example, some people prefer throwing exceptions, while others are concerned
85−with purity. Just define `handleHttpException` accordingly when making your
86−monad instance of `MonadHttp` and it will play together seamlessly. Finally,
87−the library cuts down boilerplate considerably, and helps you write concise,
88−easy to read, and maintainable code.
66+type level.
67+
68+“Expandable” refers to the ability to create new components without having
69+to resort to hacking. For example, it's possible to define your own HTTP
70+methods, create new ways to construct the body of a request, create new
71+authorization options, perform a request in a different way, and create your
72+own methods to parse a response.
8973
9074The library uses the following mature packages under the hood to guarantee
9175you the best experience:
@@ -95,89 +79,11 @@ you the best experience:
9579* [`http-client-tls`](https://hackage.haskell.org/package/http-client-tls)—TLS
9680 (HTTPS) support for `http-client`.
9781
98−It's important to note that since we leverage well-known libraries that the
82+It is important to note that since we leverage well-known libraries that the
9983whole Haskell ecosystem uses, there is no risk in using Req. The machinery
10084for performing requests is the same as with `http-conduit` and Wreq. The
10185only difference is the API.
10286
103−## Motivation and Req vs other libraries
104−
105−*This section is my opinion and it contains criticisms of other well-known
106−libraries. If you're a user/fan of one of these libraries, please remember
107−not to react aggressively and respect the fact that I may have different
108−views on API design from yours.*
109−
110−I have spent time to write the library because sending HTTP requests is a
111−common need, but there is no high-level library for that in Haskell that I
112−could use with pleasure. I'll explain why.
113−
114−First of all, there is `http-client` and `http-client-tls`. They just work.
115−I have no issues with the libraries except that they are too low-level for
116−my taste. Indeed, even the docs say that they are low-level and “intended as
117−a base layer for more user-friendly packages”. This is exactly how I use
118−them in Req, as base level. Req is nothing but a different API to
119−`http-client`, so it only works because of the hard work put into
120−`http-client`.
121−
122−`http-conduit` definitely has its place. For one thing it allows you to
123−stream request and response bodies in constant memory, what other library
124−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
126−API”, it's mostly the same as vanilla `http-client` in spirit/approach and
127−just adds `conduit`-powered functions to perform requests and allows to use
128−global implicit `Manager` (Req does the same). If I tried to frame what
129−exactly I don't like about `http-conduit` in words, then it would be “the
130−way requests are constructed”. You *set* parameters instead of *being
131−forced* to declare necessary bits and *being allowed* to declare optional
132−bits in a way that their combination is valid. Also, with `http-conduit` you
133−parse request from a string without the protection of TH that otherwise
134−saves the day as in Yesod.
135−
136−Then there is Wreq. `wreq` [doesn't see much development
137−lately](https://github.com/bos/wreq/issues/93). `wreq` is by itself a weird
138−library, IMO. You have functions per method—not very good, as there may be
139−new methods, like PATCH which is not new but still missing (well, you have
140−`customMethod`, but what is the point of having per-method functions if you
141−have a more general way to use any method? you should be able to just insert
142−methods in the “argument slot” of `customMethod` and end up with a more
143−general solution). Now, every method function has a companion that takes
144−`Options` (like you have `get` and `getWith`). Why the duplication? Where is
145−generality and flexibility? This is not all though, because you cannot
146−really use `get` you see in the main module, because you want to have
147−connection sharing. Wreq's author does not take the gift of automatic
148−connection re-use `Manager` from `http-client` provides, he invents the
149−whole new thing of “sessions”. Only inside a session your connections will
150−be shared and re-used. However with the session stuff you have yet another
151−set of per-method functions like `get` and `getWith`—these are different
152−ones, to be used with sessions! Now if you have a multi-threaded app, here
153−is a surprise for you: you can't share connections between threads as
154−connections are shared only inside of the `withSession` friend and “session
155−will no longer be valid after that function returns”. There are valid uses
156−for sessions, but the point is that they are just too inconvenient for
157−common tasks.
158−
159−I used `servant-client` a couple of times but the amount of boilerplate it
160−requires is frightening. If you have several query parameters, and you use
161−just one of them, you'll have to pass lots of `Nothing`s.
162−
163−## Unsolved problems
164−
165−AWS request signing is problematic because request body can be in the form
166−of an action to execute (and all that “popper” stuff for streaming), not
167−just a `ByteString` and so getting its digest (hash) is not trivial without
168−running the action and consuming body in its entirety before the request in
169−made. In Wreq the author chose to just use `error` when body is not a
170−(strict or lazy) `ByteString`. Maybe it's OK for Wreq, but I don't consider
171−this a proper solution for Req as we support full variety of body options.
172−For example, what if I want to upload 1 Gb file to S3? I want to stream it
173−in constant memory but at the same time I need to calculate its hash before
174−I start streaming. One solution to the problem seems to be in taking the
175−hash explicitly (as an argument of the hypothetical `awsAuth`) and making it
176−a responsibility of the user to calculate the hash correctly. I don't like
177−this because it's not user-friendly. So the question stays open, for now
178−there is no AWS signing functionality provided out-of-the-box. The best
179−solution for talking to AWS is the `amazonka` package so far.
180−
18187## Related packages
18288
18389The following packages are designed to be used with Req:
httpbin-tests/Network/HTTP/ReqSpec.hs+4−5
@@ -394,14 +394,13 @@ instance MonadHttp IO where
394394----------------------------------------------------------------------------
395395-- Helpers
396396
397−-- | Run request with such settings that it does not signal error on adverse
398−-- response status codes.
397+-- | Run a request with such settings that it does not signal errors.
399398prepareForShit :: Req a -> IO a
400399prepareForShit = runReq defaultHttpConfig {httpConfigCheckResponse = noNoise}
401400 where
402401 noNoise _ _ _ = Nothing
403402
404−-- | Run request with such settings that it throws on any response.
403+-- | Run a request with such settings that it throws on any response.
405404blindlyThrowing :: Req a -> IO a
406405blindlyThrowing = runReq defaultHttpConfig {httpConfigCheckResponse = doit}
407406 where
@@ -461,11 +460,11 @@ selector404
461460 L.responseStatus response == Y.status404 && not (B.null chunk)
462461selector404 _ = False
463462
464−-- | Empty JSON 'Object'.
463+-- | The empty JSON 'Object'.
465464emptyObject :: Value
466465emptyObject = Object HM.empty
467466
468−-- | Get rendered JSON value as 'Text'.
467+-- | Get a rendered JSON value as 'Text'.
469468reflectJSON :: ToJSON a => a -> Text
470469reflectJSON = T.decodeUtf8 . BL.toStrict . A.encode
471470
pure-tests/Network/HTTP/ReqSpec.hs+2−2
@@ -562,14 +562,14 @@ uriPort def uri =
562562 maybe def (fromIntegral) $
563563 either (const Nothing) Just (URI.uriAuthority uri) >>= URI.authPort
564564
565−-- | Get path from 'URI'.
565+-- | Get the path from a 'URI'.
566566uriPath :: URI -> ByteString
567567uriPath uri = fromMaybe "" $ do
568568 (trailingSlash, xs) <- URI.uriPath uri
569569 let pref = (encodePathPieces . fmap URI.unRText . NE.toList) xs
570570 return $ if trailingSlash then pref <> "/" else pref
571571
572−-- | Get query string from 'URI'.
572+-- | Get the query string from a 'URI'.
573573uriQuery :: URI -> ByteString
574574uriQuery uri = do
575575 let liftQueryParam = \case
req.cabal+5−9
@@ -8,12 +8,8 @@ author: Mark Karpov <markkarpov92@gmail.com>
88tested-with: ghc ==8.6.5 ghc ==8.8.4 ghc ==8.10.3
99homepage: https://github.com/mrkkrp/req
1010bug-reports: https://github.com/mrkkrp/req/issues
11−synopsis:
12− Easy-to-use, type-safe, expandable, high-level HTTP client library
13−
14−description:
15− Easy-to-use, type-safe, expandable, high-level HTTP client library.
16−
11+synopsis: HTTP client library
12+description: HTTP client library.
1713category: Network, Web
1814build-type: Simple
1915data-files:
@@ -57,7 +53,7 @@ library
5753 text >=0.2 && <1.3,
5854 time >=1.2 && <1.10,
5955 transformers >=0.4 && <0.6,
60− transformers-base -any,
56+ transformers-base,
6157 unliftio-core >=0.1.1 && <0.3
6258
6359 if flag(dev)
@@ -91,7 +87,7 @@ test-suite pure-tests
9187 http-types >=0.8 && <10.0,
9288 modern-uri >=0.3 && <0.4,
9389 mtl >=2.0 && <3.0,
94− req -any,
90+ req,
9591 retry >=0.8 && <0.9,
9692 template-haskell >=2.14 && <2.17,
9793 text >=0.2 && <1.3,
@@ -120,7 +116,7 @@ test-suite httpbin-tests
120116 http-types >=0.8 && <10.0,
121117 monad-control >=1.0 && <1.1,
122118 mtl >=2.0 && <3.0,
123− req -any,
119+ req,
124120 text >=0.2 && <1.3,
125121 unordered-containers >=0.2.5 && <0.3
126122