@@ -7,7 +7,168 @@
77[](https://travis-ci.org/mrkkrp/req)
88[](https://coveralls.io/github/mrkkrp/req?branch=master)
99
10−Library for safe construction of HTTP requests.
10+* [Motivation and Req vs other libraries](#motivation-and-req-vs-other-libraries)
11+* [Unsolved problems](#unsolved-problems)
12+* [Related packages](#related-packages)
13+* [Contribution](#contribution)
14+* [License](#license)
15+
16+This is an easy-to-use, type-safe, expandable, high-level HTTP library that
17+just works without any fooling around.
18+
19+What does the “easy-to-use” phrase mean? It means that the library is
20+designed to be beginner-friendly, so it's simple to add it to your monad
21+stack, intuitive to work with, well-documented, and does not get in your
22+way. Doing HTTP requests is a common task and Haskell library for this
23+should be very approachable and clear to beginners, thus certain compromises
24+were made. For example, one cannot currently modify `ManagerSettings` of
25+default manager because the library always uses the same implicit global
26+manager for simplicity and maximal connection sharing. There is a way to use
27+your own manager with different settings, but it requires a bit more typing.
28+
29+“Type-safe” means that the library is protective and eliminates certain
30+class of errors. For example, we have correct-by-construction URLs, it's
31+guaranteed that user does not send request body when using methods like GET
32+or OPTIONS, amount of implicit assumptions is minimized by making user
33+specify his/her intentions in explicit form (for example, it's not possible
34+to avoid specifying body or method of a request). Authentication methods
35+that assume TLS force user to use TLS on type level. The library carefully
36+hides underlying types from lower-level `http-client` package because it's
37+not safe enough (for example `Request` is an instance of `IsString` and if
38+it's malformed, it will blow up at run-time).
39+
40+“Expandable” refers to the ability of the library to be expanded without
41+ugly hacking. For example, it's possible to define your own HTTP methods,
42+new ways to construct body of request, new authorization options, new ways
43+to actually perform request and how to represent/parse response. As user
44+extends the library to satisfy his/her special needs, the new solutions work
45+just like built-ins. That said, all common cases are covered by the library
46+out-of-the-box.
47+
48+“High-level” means that there are less details to worry about. The library
49+is a result of my experiences as a Haskell consultant, working for several
50+clients who have very different projects and so the library adapts easily to
51+any particular style of writing Haskell applications. For example, some
52+people prefer throwing exceptions, while others are concerned with purity:
53+just define `handleHttpException` accordingly when making your monad
54+instance of `MonadHttp` and it will play seamlessly. Finally, the library
55+cuts boilerplate considerably and helps write concise, easy to read and
56+maintain code.
57+
58+The library uses the following mature packages under the hood to guarantee
59+you best experience without bugs or other funny business:
60+
61+* [`http-client`](https://hackage.haskell.org/package/http-client) — low
62+ level HTTP client used everywhere in Haskell.
63+
64+* [`http-client-tls`](https://hackage.haskell.org/package/http-client-tls) —
65+ TLS (HTTPS) support for `http-client`.
66+
67+It's important to note that since we leverage well-known libraries that the
68+whole Haskell ecosystem uses, there is no risk in using Req, as the
69+machinery for performing requests is the same as with `http-conduit` and
70+Wreq, it's just the API is different.
71+
72+## Motivation and Req vs other libraries
73+
74+*This section is my opinion and it contains criticisms of other well-known
75+libraries. If you're user/fan of one of these libraries, please remember not
76+to react aggressively and respect the fact that I may have different views
77+on API design from yours.*
78+
79+I have spent time to write the library because sending HTTP requests is such
80+a common thing and still there is no high-level library for that in Haskell
81+that I could use with pleasure. I'll explain why.
82+
83+First of all there is `http-client` and `http-client-tls`. They just work. I
84+have no issues with the libraries except that they are too low-level for my
85+taste. Indeed, even the docs say that they are low-level and “intended as a
86+base layer for more user-friendly packages”. This is exactly how I use them
87+in Req, as base level. Req is nothing but a different API to `http-client`,
88+so it only works because of hard work put into `http-client`.
89+
90+`http-conduit` definitely has its place. For one thing it allows you to
91+stream request and response bodies in constant memory, what other library
92+allows you to do that? On the other hand if you take a look at
93+`Network.HTTP.Simple`, then although it's said that it's a “higher level
94+API”, it's mostly the same as vanilla `http-client` in spirit/approach and
95+just adds `conduit`-powered functions to perform requests and allows to use
96+global implicit `Manager` (super-cool idea, BTW, Req does the same). If I
97+tried to frame what exactly I don't like about `http-conduit` in words, then
98+it would be “the way requests are constructed”. You set, set, set instead of
99+*being forced* to declare necessary bits and *being allowed* to declare
100+optional bits in a way that their combination is certainly valid. And you
101+parse request from a string without the protection of TH that otherwise
102+saves the day as in Yesod.
103+
104+Then there is Wreq.
105+`wreq`
106+[doesn't see much development lately](https://github.com/bos/wreq/issues/93).
107+`wreq` is by itself a weird library, IMO. You have functions per method —
108+not very good, as there may be new methods, like PATCH which is not new but
109+still missing (well you have `customMethod`, but what is the point of having
110+per-method functions if you have a more general way to use any method? you
111+should be able just to insert methods in the “argument slot” of
112+`customMethod` and end up with a more general solution). Now every method
113+function has a companion that takes `Options` (like you have `get` and
114+`getWith`). Why the duplication? Where is generality and flexibility? This
115+is not all though, because you cannot really use `get` you see in the main
116+module, because you want to have connection sharing. Wreq's author does not
117+take the gift `Manager` from `http-client` provides, no, too simple, it
118+invents the whole new thing of “sessions”. Only inside a session your
119+connections will be shared and re-used. However with the session stuff you
120+have yet another set of per-method functions like `get` and `getWith` —
121+these are different ones, to be used with sessions! Now if you have
122+multi-threaded app, here is a surprise for you: you can't share connections
123+between threads as connections are shared only inside `withSession` friend
124+and “session will no longer be valid after that function returns”.
125+Disclaimer: I mostly don't use Wreq, see below. If something in this
126+paragraph is not correct, please let me know and I'll remove it.
127+
128+It's funny that one client I worked for had to have his own little wrapper
129+around `http-client` just because he could not possibly use `wreq` and
130+`http-client` and friends were too low-level. The previous paragraph
131+extracted from a talk with a Haskell developer who works for that client.
132+Then I thought to myself “something is wrong with HTTP client libraries in
133+Haskell if they had to make a wrapper”.
134+
135+What else? I used `servant-client` a couple of times but amount of
136+boilerplate is too high. If you have several query parameters, and you use
137+just one of them, good luck passing lots of `Nothing`s.
138+
139+## Unsolved problems
140+
141+AWS request signing is problematic because request body can be in form of
142+action to execute (and all that “popper” stuff for streaming), not just
143+`ByteString` and so getting its digest (hash) is not trivial without running
144+the action and consuming body in its entirety before the request in made. In
145+Wreq the author chose to just use `error` when body is not a (strict or
146+lazy) `ByteString`. Maybe it's OK for Wreq, but I don't consider this proper
147+solution for Req as we support full variety of body options. For example
148+what if I want to upload 1 Gb file to S3? I want to stream it in constant
149+memory but at the same time I need to calculate its hash before I start
150+streaming. One solution to the problem seems to be in taking the hash
151+explicitly (as an argument of hypothetical `awsAuth`) and making it
152+responsibility of library user to calculate the hash correctly. I don't like
153+this because it's not user-friendly. So the question stays open, for now
154+there is no AWS signing functionality provided out-of-the-box.
155+
156+## Related packages
157+
158+The following packages are designed to be used with Req:
159+
160+* [`req-conduit`](https://hackage.haskell.org/package/req-conduit) — support
161+ for streaming request and response bodies in constant memory.
162+
163+If you happen to have written a package that adds new features to Req,
164+please submit a PR to include it in this list.
165+
166+## Contribution
167+
168+Issues, bugs, and questions may be reported in [the GitHub issue tracker for
169+this project](https://github.com/mrkkrp/req/issues).
170+
171+Pull requests are also welcome and will be reviewed quickly.
11172
12173## License
13174