diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## Req 3.9.1
+
+* Builds with GHC 9.0.
+
 ## Req 3.9.0
 
 * The `useHttpURI` and `useHttpsURI` functions now preserve trailing
diff --git a/Network/HTTP/Req.hs b/Network/HTTP/Req.hs
--- a/Network/HTTP/Req.hs
+++ b/Network/HTTP/Req.hs
@@ -30,61 +30,40 @@
 --
 -- The documentation below is structured in such a way that the most
 -- important information is presented first: you learn how to do HTTP
--- requests, how to embed them in any monad you have, and then it gives you
+-- requests, how to embed them in the monad you have, and then it gives you
 -- details about less-common things you may want to know about. The
 -- documentation is written with sufficient coverage of details and
 -- examples, and it's designed to be a complete tutorial on its own.
 --
--- /(A modest intro goes here, click on 'req' to start making requests.)/
---
 -- === About the library
 --
--- Req is an easy-to-use, type-safe, expandable, high-level HTTP client
--- library that just works without any fooling around.
---
--- What does the phrase “easy-to-use” mean? It means that the library is
--- designed to be beginner-friendly so it's simple to add to your monad
--- stack, intuitive to work with, well-documented, and does not get in your
--- way. Doing HTTP requests is a common task and Haskell library for this
--- should be very approachable and clear to beginners, thus certain
--- compromises were made. For example, one cannot currently modify
--- 'L.ManagerSettings' of the default manager because the library always
--- uses the same implicit global manager for simplicity and maximal
--- connection sharing. There is a way to use your own manager with different
--- settings, but it requires a bit more typing.
+-- Req is an HTTP client library that attempts to be easy-to-use, type-safe,
+-- and expandable.
 --
--- “Type-safe” means that the library is protective and eliminates certain
--- classes of errors. For example, we have correct-by-construction 'Url's,
--- it's guaranteed that the user does not send the request body when using
--- methods like 'GET' or 'OPTIONS', and the amount of implicit assumptions
--- is minimized by making the user specify his\/her intentions in an
--- explicit form (for example, it's not possible to avoid specifying the
--- body or method of request). Authentication methods that assume HTTPS
--- force the user to use HTTPS at the type level. The library also carefully
--- hides underlying types from the lower-level @http-client@ package because
--- those types are not safe enough (for example 'L.Request' is an instance
--- of 'Data.String.IsString' and, if it's malformed, it will blow up at
--- run-time).
+-- “Easy-to-use” means that the library is designed to be beginner-friendly
+-- so it's simple to add to your monad stack, intuitive to work with,
+-- well-documented, and does not get in your way. Doing HTTP requests is a
+-- common task and a Haskell library for this should be approachable and
+-- clear to beginners, thus certain compromises were made. For example, one
+-- cannot currently modify 'L.ManagerSettings' of the default manager
+-- because the library always uses the same implicit global manager for
+-- simplicity and maximal connection sharing. There is a way to use your own
+-- manager with different settings, but it requires more typing.
 --
--- “Expandable” refers to the ability of the library to be expanded without
--- having to resort to ugly hacking. For example, it's possible to define
--- your own HTTP methods, create new ways to construct the body of a
--- request, create new authorization options, perform a request in a
--- different way, and create your own methods to parse and represent a
--- response. As the user extends the library to satisfy his\/her special
--- needs, the new solutions will work just like the built-ins. However, all
--- of the common cases are also covered by the library out-of-the-box.
+-- “Type-safe” means that the library tries to eliminate certain classes of
+-- errors. For example, we have correct-by-construction URLs; it is
+-- guaranteed that the user does not send the request body when using
+-- methods like GET or OPTIONS, and the amount of implicit assumptions is
+-- minimized by making the user specify their intentions in an explicit
+-- form. For example, it's not possible to avoid specifying the body or the
+-- method of a request. Authentication methods that assume HTTPS force the
+-- user to use HTTPS at the type level.
 --
--- “High-level” means that there are less details to worry about. The
--- library is a result of my experiences as a Haskell consultant. Working
--- for several clients, who had very different projects, showed me that the
--- library should adapt easily to any particular style of writing Haskell
--- applications. For example, some people prefer throwing exceptions, while
--- others are concerned with purity. Just define 'handleHttpException'
--- accordingly when making your monad instance of 'MonadHttp' and it will
--- play together seamlessly. Finally, the library cuts down boilerplate
--- considerably, and helps you write concise, easy to read, and maintainable
--- code.
+-- “Expandable” refers to the ability to create new components without
+-- having to resort to hacking. For example, it's possible to define your
+-- own HTTP methods, create new ways to construct the body of a request,
+-- create new authorization options, perform a request in a different way,
+-- and create your own methods to parse a response.
 --
 -- === Using with other libraries
 --
@@ -303,7 +282,7 @@
 --
 -- @body@ is a body option such as 'NoReqBody' or 'ReqBodyJson'. The
 -- tutorial has a section about HTTP bodies, but usage is very
--- straightforward and should be clear from the examples below.
+-- straightforward and should be clear from the examples.
 --
 -- @response@ is a type hint how to make and interpret response of an HTTP
 -- request. Out-of-the-box it can be the following:
@@ -588,9 +567,9 @@
           nubHeaders
             <> getRequestMod options
             <> getRequestMod config
-            <> getRequestMod (Womb body :: Womb "body" body)
+            <> getRequestMod (Tagged body :: Tagged "body" body)
             <> getRequestMod url
-            <> getRequestMod (Womb method :: Womb "method" method)
+            <> getRequestMod (Tagged method :: Tagged "method" method)
   request <- finalizeRequest options request'
   withReqManager (m request)
 
@@ -600,10 +579,10 @@
 withReqManager :: MonadIO m => (L.Manager -> m a) -> m a
 withReqManager m = liftIO (readIORef globalManager) >>= m
 
--- | Global 'L.Manager' that 'req' uses. Here we just go with the default
--- settings, so users don't need to deal with this manager stuff at all, but
--- when we create a request, instance 'HttpConfig' can affect the default
--- settings via 'getHttpConfig'.
+-- | The global 'L.Manager' that 'req' uses. Here we just go with the
+-- default settings, so users don't need to deal with this manager stuff at
+-- all, but when we create a request, instance 'HttpConfig' can affect the
+-- default settings via 'getHttpConfig'.
 --
 -- A note about safety, in case 'unsafePerformIO' looks suspicious to you.
 -- The value of 'globalManager' is named and lives on top level. This means
@@ -634,8 +613,8 @@
 -- When writing a library, keep your API polymorphic in terms of
 -- 'MonadHttp', only define instance of 'MonadHttp' in final application.
 -- Another option is to use a @newtype@-wrapped monad stack and define
--- 'MonadHttp' for it. As of version /0.4.0/, the 'Req' monad that follows
--- this strategy is provided out-of-the-box (see below).
+-- 'MonadHttp' for it. As of the version /0.4.0/, the 'Req' monad that
+-- follows this strategy is provided out-of-the-box (see below).
 
 -- | A type class for monads that support performing HTTP requests.
 -- Typically, you only need to define the 'handleHttpException' method
@@ -648,17 +627,16 @@
   -- 'Control.Monad.Except.throwError'.
   handleHttpException :: HttpException -> m a
 
-  -- | Return 'HttpConfig' to be used when performing HTTP requests. Default
-  -- implementation returns its 'def' value, which is described in the
-  -- documentation for the type. Common usage pattern with manually defined
-  -- 'getHttpConfig' is to return some hard-coded value, or a value
+  -- | Return the 'HttpConfig' to be used when performing HTTP requests.
+  -- Default implementation returns its 'def' value, which is described in
+  -- the documentation for the type. Common usage pattern with manually
+  -- defined 'getHttpConfig' is to return some hard-coded value, or a value
   -- extracted from 'Control.Monad.Reader.MonadReader' if a more flexible
   -- approach to configuration is desirable.
   getHttpConfig :: m HttpConfig
   getHttpConfig = return defaultHttpConfig
 
--- | 'HttpConfig' contains general and default settings to be used when
--- making HTTP requests.
+-- | 'HttpConfig' contains settings to be used when making HTTP requests.
 data HttpConfig = HttpConfig
   { -- | Proxy to use. By default values of @HTTP_PROXY@ and @HTTPS_PROXY@
     -- environment variables are respected, this setting overwrites them.
@@ -729,7 +707,7 @@
   }
   deriving (Typeable)
 
--- | Default value of 'HttpConfig'.
+-- | The default value of 'HttpConfig'.
 --
 -- @since 2.0.0
 defaultHttpConfig :: HttpConfig
@@ -773,7 +751,7 @@
         LI.requestManagerOverride = httpConfigAltManager
       }
 
--- | A monad that allows to run 'req' in any 'IO'-enabled monad without
+-- | A monad that allows us to run 'req' in any 'IO'-enabled monad without
 -- having to define new instances.
 --
 -- @since 0.4.0
@@ -810,7 +788,7 @@
   getHttpConfig = Req ask
 
 -- | Run a computation in the 'Req' monad with the given 'HttpConfig'. In
--- case of exceptional situation an 'HttpException' will be thrown.
+-- the case of an exceptional situation an 'HttpException' will be thrown.
 --
 -- @since 0.4.0
 runReq ::
@@ -919,7 +897,7 @@
   -- | Return name of the method as a 'ByteString'.
   httpMethodName :: Proxy a -> ByteString
 
-instance HttpMethod method => RequestComponent (Womb "method" method) where
+instance HttpMethod method => RequestComponent (Tagged "method" method) where
   getRequestMod _ = Endo $ \x ->
     x {L.method = httpMethodName (Proxy :: Proxy method)}
 
@@ -966,7 +944,7 @@
 type role Url nominal
 
 -- With template-haskell >=2.15 and text >=1.2.4 Lift can be derived, however
--- the derived lift forgets the type of scheme.
+-- the derived lift forgets the type of the scheme.
 instance Typeable scheme => TH.Lift (Url scheme) where
   lift url =
     TH.dataToExpQ (fmap liftText . cast) url `TH.sigE` case url of
@@ -975,8 +953,10 @@
     where
       liftText t = TH.AppE (TH.VarE 'T.pack) <$> TH.lift (T.unpack t)
 
-#if MIN_VERSION_template_haskell(2,16,0)
-  liftTyped url = TH.TExp <$> TH.lift url
+#if MIN_VERSION_template_haskell(2,17,0)
+  liftTyped = TH.Code . TH.unsafeTExpCoerce . TH.lift
+#elif MIN_VERSION_template_haskell(2,16,0)
+  liftTyped = TH.unsafeTExpCoerce . TH.lift
 #endif
 
 -- | Given host name, produce a 'Url' which has “http” as its scheme and
@@ -989,14 +969,14 @@
 https :: Text -> Url 'Https
 https = Url Https . pure
 
--- | Grow given 'Url' appending a single path segment to it. Note that the
+-- | Grow a given 'Url' appending a single path segment to it. Note that the
 -- path segment can be of any type that is an instance of 'ToHttpApiData'.
 infixl 5 /~
 
 (/~) :: ToHttpApiData a => Url scheme -> a -> Url scheme
 Url secure path /~ segment = Url secure (NE.cons (toUrlPiece segment) path)
 
--- | Type-constrained version of @('/~')@ to remove ambiguity in the cases
+-- | A type-constrained version of @('/~')@ to remove ambiguity in the cases
 -- when next URL piece is a 'Data.Text.Text' literal.
 infixl 5 /:
 
@@ -1172,10 +1152,10 @@
 instance HttpBody NoReqBody where
   getRequestBody NoReqBody = L.RequestBodyBS B.empty
 
--- | This body option allows to use a JSON object as request body—probably
--- the most popular format right now. Just wrap a data type that is an
--- instance of 'ToJSON' type class and you are done: it will be converted to
--- JSON and inserted as request body.
+-- | This body option allows us to use a JSON object as the request
+-- body—probably the most popular format right now. Just wrap a data type
+-- that is an instance of 'ToJSON' type class and you are done: it will be
+-- converted to JSON and inserted as request body.
 --
 -- This body option sets the @Content-Type@ header to @\"application/json;
 -- charset=utf-8\"@ value.
@@ -1186,7 +1166,7 @@
   getRequestContentType _ = pure "application/json; charset=utf-8"
 
 -- | This body option streams request body from a file. It is expected that
--- the file size does not change during the streaming.
+-- the file size does not change during streaming.
 --
 -- Using of this body option does not set the @Content-Type@ header.
 newtype ReqBodyFile = ReqBodyFile FilePath
@@ -1211,12 +1191,11 @@
 instance HttpBody ReqBodyLbs where
   getRequestBody (ReqBodyLbs bs) = L.RequestBodyLBS bs
 
--- | Form URL-encoded body. This can hold a collection of parameters which
--- are encoded similarly to query parameters at the end of query string,
--- with the only difference that they are stored in request body. The
--- similarity is reflected in the API as well, as you can use the same
--- combinators you would use to add query parameters: @('=:')@ and
--- 'queryFlag'.
+-- | URL-encoded body. This can hold a collection of parameters which are
+-- encoded similarly to query parameters at the end of query string, with
+-- the only difference that they are stored in request body. The similarity
+-- is reflected in the API as well, as you can use the same combinators you
+-- would use to add query parameters: @('=:')@ and 'queryFlag'.
 --
 -- This body option sets the @Content-Type@ header to
 -- @\"application/x-www-form-urlencoded\"@ value.
@@ -1302,9 +1281,6 @@
 -- | This type function allows any HTTP body if method says it
 -- 'CanHaveBody'. When the method says it should have 'NoBody', the only
 -- body option to use is 'NoReqBody'.
---
--- __Note__: users of GHC 8.0.1 and later will see a slightly more friendly
--- error message when method does not allow a body and body is provided.
 type family
   HttpBodyAllowed
     (allowsBody :: CanHaveBody)
@@ -1317,8 +1293,8 @@
     TypeError
       ('Text "This HTTP method does not allow attaching a request body.")
 
-instance HttpBody body => RequestComponent (Womb "body" body) where
-  getRequestMod (Womb body) = Endo $ \x ->
+instance HttpBody body => RequestComponent (Tagged "body" body) where
+  getRequestMod (Tagged body) = Endo $ \x ->
     x
       { L.requestBody = getRequestBody body,
         L.requestHeaders =
@@ -1347,8 +1323,8 @@
   = Option (Endo (Y.QueryText, L.Request)) (Maybe (L.Request -> IO L.Request))
 
 -- NOTE 'QueryText' is just [(Text, Maybe Text)], we keep it along with
--- Request to avoid appending to existing query string in request every
--- time new parameter is added. Additional Maybe (L.Request -> IO
+-- Request to avoid appending to an existing query string in request every
+-- time new parameter is added. The additional Maybe (L.Request -> IO
 -- L.Request) is a finalizer that will be applied after all other
 -- transformations. This is for authentication methods that sign requests
 -- based on data in Request.
@@ -1405,7 +1381,7 @@
 (=:) :: (QueryParam param, ToHttpApiData a) => Text -> a -> param
 name =: value = queryParam name (pure value)
 
--- | Construct a flag, that is, valueless query parameter. For example, in
+-- | Construct a flag, that is, a valueless query parameter. For example, in
 -- the following URL @\"a\"@ is a flag, while @\"b\"@ is a query parameter
 -- with a value:
 --
@@ -1595,7 +1571,7 @@
 
 -- | Specify the port to connect to explicitly. Normally, 'Url' you use
 -- determines the default port: @80@ for HTTP and @443@ for HTTPS. This
--- 'Option' allows to choose an arbitrary port overwriting the defaults.
+-- 'Option' allows us to choose an arbitrary port overwriting the defaults.
 port :: Int -> Option scheme
 port n = withRequest $ \x ->
   x {L.port = n}
@@ -1610,8 +1586,8 @@
 --
 -- > decompress (const True)
 decompress ::
-  -- | Predicate that is given MIME type, it
-  -- returns 'True' when content should be decompressed on the fly.
+  -- | Predicate that is given MIME type, it returns 'True' when content
+  -- should be decompressed on the fly.
   (ByteString -> Bool) ->
   Option scheme
 decompress f = withRequest $ \x ->
@@ -1713,7 +1689,7 @@
 ----------------------------------------------------------------------------
 -- Helpers for response interpretations
 
--- | Fetch beginning of response and return it together with new
+-- | Fetch beginning of the response and return it together with a new
 -- @'L.Response' 'L.BodyReader'@ that can be passed to 'getHttpResponse' and
 -- such.
 grabPreview ::
@@ -1825,9 +1801,9 @@
 -- To create a new response interpretation you just need to make your data
 -- type an instance of the 'HttpResponse' type class.
 
--- | A type class for response interpretations. It allows to describe how to
--- consume response from a @'L.Response' 'L.BodyReader'@ and produce the
--- final result that is to be returned to the user.
+-- | A type class for response interpretations. It allows us to describe how
+-- to consume the response from a @'L.Response' 'L.BodyReader'@ and produce
+-- the final result that is to be returned to the user.
 class HttpResponse response where
   -- | The associated type is the type of body that can be extracted from an
   -- instance of 'HttpResponse'.
@@ -1891,7 +1867,7 @@
 -- method@ and @'HttpBody' body => 'RequestComponent' body@ when it decides
 -- which instance to use (i.e. the constraints are taken into account later,
 -- when instance is already chosen).
-newtype Womb (tag :: Symbol) a = Womb a
+newtype Tagged (tag :: Symbol) a = Tagged a
 
 -- | Exceptions that this library throws.
 data HttpException
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -43,49 +43,33 @@
   liftIO $ print (responseBody r :: Value)
 ```
 
-Req is an easy-to-use, type-safe, expandable, high-level HTTP client library
-that just works without any fooling around.
+Req is an HTTP client library that attempts to be easy-to-use, type-safe,
+and expandable.
 
-What does the phrase “easy-to-use” mean? It means that the library is
-designed to be beginner-friendly so it's simple to add to your monad stack,
-intuitive to work with, well-documented, and does not get in your way. Doing
-HTTP requests is a common task and Haskell library for this should be very
-approachable and clear to beginners, thus certain compromises were made. For
-example, one cannot currently modify `ManagerSettings` of the default
-manager because the library always uses the same implicit global manager for
-simplicity and maximal connection sharing. There is a way to use your own
-manager with different settings, but it requires a bit more typing.
+“Easy-to-use” means that the library is designed to be beginner-friendly so
+it's simple to add to your monad stack, intuitive to work with,
+well-documented, and does not get in your way. Doing HTTP requests is a
+common task and a Haskell library for this should be approachable and clear
+to beginners, thus certain compromises were made. For example, one cannot
+currently modify `ManagerSettings` of the default manager because the
+library always uses the same implicit global manager for simplicity and
+maximal connection sharing. There is a way to use your own manager with
+different settings, but it requires more typing.
 
-“Type-safe” means that the library is protective and eliminates certain
-classes of errors. For example, we have correct-by-construction URLs, it's
-guaranteed that the user does not send the request body when using methods
-like GET or OPTIONS, and the amount of implicit assumptions is minimized by
-making the user specify his/her intentions in an explicit form (for example,
-it's not possible to avoid specifying the body or method of request).
+“Type-safe” means that the library tries to eliminate certain classes of
+errors. For example, we have correct-by-construction URLs; it is guaranteed
+that the user does not send the request body when using methods like GET or
+OPTIONS, and the amount of implicit assumptions is minimized by making the
+user specify their intentions in an explicit form. For example, it's not
+possible to avoid specifying the body or the method of a request.
 Authentication methods that assume HTTPS force the user to use HTTPS at the
-type level. The library also carefully hides underlying types from the
-lower-level `http-client` package because those types are not safe enough
-(for example `Request` is an instance of `IsString` and, if it's malformed,
-it will blow up at run-time).
-
-“Expandable” refers to the ability to create new components for dealing with
-HTTP without having to resort to ugly hacking. For example, it's possible to
-define your own HTTP methods, create new ways to construct the body of a
-request, create new authorization options, perform a request in a different
-way, and create your own methods to parse and represent a response. As the
-user extends the library to satisfy his/her special needs, the new solutions
-will work just like the built-ins. However, all of the common cases are also
-covered by the library out-of-the-box.
+type level.
 
-“High-level” means that there are less details to worry about. The library
-is a result of my experiences as a Haskell consultant. Working for several
-clients, who had very different projects, showed me that the library should
-adapt easily to any particular style of writing Haskell applications. For
-example, some people prefer throwing exceptions, while others are concerned
-with purity. Just define `handleHttpException` accordingly when making your
-monad instance of `MonadHttp` and it will play together seamlessly. Finally,
-the library cuts down boilerplate considerably, and helps you write concise,
-easy to read, and maintainable code.
+“Expandable” refers to the ability to create new components without having
+to resort to hacking. For example, it's possible to define your own HTTP
+methods, create new ways to construct the body of a request, create new
+authorization options, perform a request in a different way, and create your
+own methods to parse a response.
 
 The library uses the following mature packages under the hood to guarantee
 you the best experience:
@@ -95,88 +79,10 @@
 * [`http-client-tls`](https://hackage.haskell.org/package/http-client-tls)—TLS
   (HTTPS) support for `http-client`.
 
-It's important to note that since we leverage well-known libraries that the
+It is important to note that since we leverage well-known libraries that the
 whole Haskell ecosystem uses, there is no risk in using Req. The machinery
 for performing requests is the same as with `http-conduit` and Wreq. The
 only difference is the API.
-
-## Motivation and Req vs other libraries
-
-*This section is my opinion and it contains criticisms of other well-known
-libraries. If you're a user/fan of one of these libraries, please remember
-not to react aggressively and respect the fact that I may have different
-views on API design from yours.*
-
-I have spent time to write the library because sending HTTP requests is a
-common need, but there is no high-level library for that in Haskell that I
-could use with pleasure. I'll explain why.
-
-First of all, there is `http-client` and `http-client-tls`. They just work.
-I have no issues with the libraries except that they are too low-level for
-my taste. Indeed, even the docs say that they are low-level and “intended as
-a base layer for more user-friendly packages”. This is exactly how I use
-them in Req, as base level. Req is nothing but a different API to
-`http-client`, so it only works because of the hard work put into
-`http-client`.
-
-`http-conduit` definitely has its place. For one thing it allows you to
-stream request and response bodies in constant memory, what other library
-allows you to do that? On the other hand if you take a look at
-`Network.HTTP.Simple`, then although it's said that it's a “higher level
-API”, it's mostly the same as vanilla `http-client` in spirit/approach and
-just adds `conduit`-powered functions to perform requests and allows to use
-global implicit `Manager` (Req does the same). If I tried to frame what
-exactly I don't like about `http-conduit` in words, then it would be “the
-way requests are constructed”. You *set* parameters instead of *being
-forced* to declare necessary bits and *being allowed* to declare optional
-bits in a way that their combination is valid. Also, with `http-conduit` you
-parse request from a string without the protection of TH that otherwise
-saves the day as in Yesod.
-
-Then there is Wreq. `wreq` [doesn't see much development
-lately](https://github.com/bos/wreq/issues/93). `wreq` is by itself a weird
-library, IMO. You have functions per method—not very good, as there may be
-new methods, like PATCH which is not new but still missing (well, you have
-`customMethod`, but what is the point of having per-method functions if you
-have a more general way to use any method? you should be able to just insert
-methods in the “argument slot” of `customMethod` and end up with a more
-general solution). Now, every method function has a companion that takes
-`Options` (like you have `get` and `getWith`). Why the duplication? Where is
-generality and flexibility? This is not all though, because you cannot
-really use `get` you see in the main module, because you want to have
-connection sharing. Wreq's author does not take the gift of automatic
-connection re-use `Manager` from `http-client` provides, he invents the
-whole new thing of “sessions”. Only inside a session your connections will
-be shared and re-used. However with the session stuff you have yet another
-set of per-method functions like `get` and `getWith`—these are different
-ones, to be used with sessions! Now if you have a multi-threaded app, here
-is a surprise for you: you can't share connections between threads as
-connections are shared only inside of the `withSession` friend and “session
-will no longer be valid after that function returns”. There are valid uses
-for sessions, but the point is that they are just too inconvenient for
-common tasks.
-
-I used `servant-client` a couple of times but the amount of boilerplate it
-requires is frightening. If you have several query parameters, and you use
-just one of them, you'll have to pass lots of `Nothing`s.
-
-## Unsolved problems
-
-AWS request signing is problematic because request body can be in the form
-of an action to execute (and all that “popper” stuff for streaming), not
-just a `ByteString` and so getting its digest (hash) is not trivial without
-running the action and consuming body in its entirety before the request in
-made. In Wreq the author chose to just use `error` when body is not a
-(strict or lazy) `ByteString`. Maybe it's OK for Wreq, but I don't consider
-this a proper solution for Req as we support full variety of body options.
-For example, what if I want to upload 1 Gb file to S3? I want to stream it
-in constant memory but at the same time I need to calculate its hash before
-I start streaming. One solution to the problem seems to be in taking the
-hash explicitly (as an argument of the hypothetical `awsAuth`) and making it
-a responsibility of the user to calculate the hash correctly. I don't like
-this because it's not user-friendly. So the question stays open, for now
-there is no AWS signing functionality provided out-of-the-box. The best
-solution for talking to AWS is the `amazonka` package so far.
 
 ## Related packages
 
diff --git a/httpbin-tests/Network/HTTP/ReqSpec.hs b/httpbin-tests/Network/HTTP/ReqSpec.hs
--- a/httpbin-tests/Network/HTTP/ReqSpec.hs
+++ b/httpbin-tests/Network/HTTP/ReqSpec.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
@@ -27,10 +26,6 @@
 import Test.Hspec
 import Test.QuickCheck
 
-#if !MIN_VERSION_base(4,13,0)
-import Data.Semigroup ((<>))
-#endif
-
 spec :: Spec
 spec = do
   describe "exception throwing on non-2xx status codes" $
@@ -394,14 +389,13 @@
 ----------------------------------------------------------------------------
 -- Helpers
 
--- | Run request with such settings that it does not signal error on adverse
--- response status codes.
+-- | Run a request with such settings that it does not signal errors.
 prepareForShit :: Req a -> IO a
 prepareForShit = runReq defaultHttpConfig {httpConfigCheckResponse = noNoise}
   where
     noNoise _ _ _ = Nothing
 
--- | Run request with such settings that it throws on any response.
+-- | Run a request with such settings that it throws on any response.
 blindlyThrowing :: Req a -> IO a
 blindlyThrowing = runReq defaultHttpConfig {httpConfigCheckResponse = doit}
   where
@@ -461,11 +455,11 @@
     L.responseStatus response == Y.status404 && not (B.null chunk)
 selector404 _ = False
 
--- | Empty JSON 'Object'.
+-- | The empty JSON 'Object'.
 emptyObject :: Value
 emptyObject = Object HM.empty
 
--- | Get rendered JSON value as 'Text'.
+-- | Get a rendered JSON value as 'Text'.
 reflectJSON :: ToJSON a => a -> Text
 reflectJSON = T.decodeUtf8 . BL.toStrict . A.encode
 
diff --git a/pure-tests/Network/HTTP/ReqSpec.hs b/pure-tests/Network/HTTP/ReqSpec.hs
--- a/pure-tests/Network/HTTP/ReqSpec.hs
+++ b/pure-tests/Network/HTTP/ReqSpec.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE FlexibleInstances #-}
@@ -48,10 +47,6 @@
 import qualified Text.URI as URI
 import qualified Text.URI.QQ as QQ
 
-#if !MIN_VERSION_base(4,13,0)
-import Data.Semigroup ((<>))
-#endif
-
 spec :: Spec
 spec = do
   describe "config" $
@@ -266,11 +261,7 @@
       it "cookie jar is set without modifications" $
         property $ \cjar -> do
           request <- req_ GET url NoReqBody (cookieJar cjar)
-#if MIN_VERSION_http_client(0,7,0)
           L.cookieJar request `shouldSatisfy` (maybe False (L.equalCookieJar cjar))
-#else
-          L.cookieJar request `shouldBe` Just cjar
-#endif
     describe "basicAuth" $ do
       it "sets Authorization header to correct value" $
         property $ \username password -> do
@@ -562,14 +553,14 @@
   maybe def (fromIntegral) $
     either (const Nothing) Just (URI.uriAuthority uri) >>= URI.authPort
 
--- | Get path from 'URI'.
+-- | Get the path from a 'URI'.
 uriPath :: URI -> ByteString
 uriPath uri = fromMaybe "" $ do
   (trailingSlash, xs) <- URI.uriPath uri
   let pref = (encodePathPieces . fmap URI.unRText . NE.toList) xs
   return $ if trailingSlash then pref <> "/" else pref
 
--- | Get query string from 'URI'.
+-- | Get the query string from a 'URI'.
 uriQuery :: URI -> ByteString
 uriQuery uri = do
   let liftQueryParam = \case
diff --git a/req.cabal b/req.cabal
--- a/req.cabal
+++ b/req.cabal
@@ -1,19 +1,15 @@
 cabal-version:   1.18
 name:            req
-version:         3.9.0
+version:         3.9.1
 license:         BSD3
 license-file:    LICENSE.md
 maintainer:      Mark Karpov <markkarpov92@gmail.com>
 author:          Mark Karpov <markkarpov92@gmail.com>
-tested-with:     ghc ==8.6.5 ghc ==8.8.4 ghc ==8.10.3
+tested-with:     ghc ==8.8.4 ghc ==8.10.4 ghc ==9.0.1
 homepage:        https://github.com/mrkkrp/req
 bug-reports:     https://github.com/mrkkrp/req/issues
-synopsis:
-    Easy-to-use, type-safe, expandable, high-level HTTP client library
-
-description:
-    Easy-to-use, type-safe, expandable, high-level HTTP client library.
-
+synopsis:        HTTP client library
+description:     HTTP client library.
 category:        Network, Web
 build-type:      Simple
 data-files:
@@ -39,25 +35,25 @@
     build-depends:
         aeson >=0.9 && <1.6,
         authenticate-oauth >=1.5 && <1.7,
-        base >=4.12 && <5.0,
+        base >=4.13 && <5.0,
         blaze-builder >=0.3 && <0.5,
         bytestring >=0.10.8 && <0.12,
         case-insensitive >=0.2 && <1.3,
         connection >=0.2.2 && <0.4,
         exceptions >=0.6 && <0.11,
         http-api-data >=0.2 && <0.5,
-        http-client >=0.5 && <0.8,
+        http-client >=0.7 && <0.8,
         http-client-tls >=0.3.2 && <0.4,
         http-types >=0.8 && <10.0,
         modern-uri >=0.3 && <0.4,
         monad-control >=1.0 && <1.1,
         mtl >=2.0 && <3.0,
         retry >=0.8 && <0.9,
-        template-haskell >=2.14 && <2.17,
+        template-haskell >=2.14 && <2.18,
         text >=0.2 && <1.3,
         time >=1.2 && <1.10,
         transformers >=0.4 && <0.6,
-        transformers-base -any,
+        transformers-base,
         unliftio-core >=0.1.1 && <0.3
 
     if flag(dev)
@@ -81,19 +77,19 @@
     build-depends:
         QuickCheck >=2.7 && <3.0,
         aeson >=0.9 && <1.6,
-        base >=4.12 && <5.0,
+        base >=4.13 && <5.0,
         blaze-builder >=0.3 && <0.5,
         bytestring >=0.10.8 && <0.12,
         case-insensitive >=0.2 && <1.3,
         hspec >=2.0 && <3.0,
         hspec-core >=2.0 && <3.0,
-        http-client >=0.5 && <0.8,
+        http-client >=0.7 && <0.8,
         http-types >=0.8 && <10.0,
         modern-uri >=0.3 && <0.4,
         mtl >=2.0 && <3.0,
-        req -any,
+        req,
         retry >=0.8 && <0.9,
-        template-haskell >=2.14 && <2.17,
+        template-haskell >=2.14 && <2.18,
         text >=0.2 && <1.3,
         time >=1.2 && <1.10
 
@@ -113,14 +109,14 @@
     build-depends:
         QuickCheck >=2.7 && <3.0,
         aeson >=0.9 && <1.6,
-        base >=4.12 && <5.0,
+        base >=4.13 && <5.0,
         bytestring >=0.10.8 && <0.12,
         hspec >=2.0 && <3.0,
-        http-client >=0.5 && <0.8,
+        http-client >=0.7 && <0.8,
         http-types >=0.8 && <10.0,
         monad-control >=1.0 && <1.1,
         mtl >=2.0 && <3.0,
-        req -any,
+        req,
         text >=0.2 && <1.3,
         unordered-containers >=0.2.5 && <0.3
 
