diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,8 @@
+### 0.3.1.0
+
+- Added function *subrequestWithRead* and an asynchronous variable handler of
+  the same name.
+
 ### 0.3.0.0
 
 - Added module *NgxExport.Tools.Subrequest* for making HTTP (sub)requests
diff --git a/NgxExport/Tools/Subrequest.hs b/NgxExport/Tools/Subrequest.hs
--- a/NgxExport/Tools/Subrequest.hs
+++ b/NgxExport/Tools/Subrequest.hs
@@ -21,17 +21,18 @@
     -- * Making HTTP subrequests
     -- $makingHTTPSubrequests
                                    subrequest
+                                  ,subrequestWithRead
                                   ) where
 
 import           NgxExport
 import           NgxExport.Tools
 
 import           Network.HTTP.Client
+import           Network.HTTP.Types
 import           Data.ByteString (ByteString)
+import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
-import qualified Data.Text as T
 import qualified Data.Text.Encoding as T
-import           Data.Text (Text)
 import           Data.CaseInsensitive (mk)
 import           Data.Aeson
 import           Control.Arrow
@@ -43,7 +44,8 @@
 -- Using asynchronous variable handlers and services together with the HTTP
 -- client from "Network.HTTP.Client" allows making HTTP subrequests easily.
 -- This module provides such functionality by exporting asynchronous variable
--- handler __/subrequest/__ and function 'subrequest' to build custom handlers.
+-- handlers __/subrequest/__ and __/subrequestWithRead/__, and functions
+-- 'subrequest' and 'subrequestWithRead' to build custom handlers.
 --
 -- Below is a simple example.
 --
@@ -106,7 +108,7 @@
 --                       \"headers\": [[\"Custom-Header\", \"$arg_a\"]]}\';
 --
 --             if ($hs_subrequest = \'\') {
---                 echo_status 500;
+--                 echo_status 404;
 --                 echo \"Failed to perform subrequest\";
 --             }
 --
@@ -165,10 +167,10 @@
 -- > In backend, Custom-Header is 'Value'
 --
 -- Let's do a nasty thing. By injecting a comma into the argument /a/ we shall
--- break parsing JSON.
+-- break JSON parsing.
 --
 -- > $ curl -D- 'http://localhost:8010/?a=Value"'
--- > HTTP/1.1 500 Internal Server Error
+-- > HTTP/1.1 404 Not Found
 -- > Server: nginx/1.17.9
 -- > Date: Mon, 30 Mar 2020 14:42:42 GMT
 -- > Content-Type: application/octet-stream
@@ -177,41 +179,38 @@
 -- >
 -- > Failed to perform subrequest
 
-type ReqHeaders = [(Text, Text)]
-
 data SubrequestParseError = SubrequestParseError deriving Show
+
 instance Exception SubrequestParseError
 
 data SubrequestConf =
-    SubrequestConf { srMethod  :: Text
+    SubrequestConf { srMethod  :: ByteString
                    , srUri     :: String
-                   , srBody    :: Text
-                   , srHeaders :: ReqHeaders
-                   }
+                   , srBody    :: ByteString
+                   , srHeaders :: RequestHeaders
+                   } deriving Read
+
 instance FromJSON SubrequestConf where
     parseJSON = withObject "SubrequestConf" $ \o -> do
-        srMethod <- o .:? "method" .!= "GET"
+        srMethod <- maybe "GET" T.encodeUtf8 <$> o .:? "method"
         srUri <- o .: "uri"
-        srBody <- o .:? "body" .!= ""
-        srHeaders <- o .:? "headers" .!= []
+        srBody <- maybe "" T.encodeUtf8 <$> o .:? "body"
+        srHeaders <- map (mk . T.encodeUtf8 *** T.encodeUtf8) <$>
+            o .:? "headers" .!= []
         return SubrequestConf {..}
 
 doSubrequest :: SubrequestConf -> IO L.ByteString
 doSubrequest SubrequestConf {..} = do
     req <- parseUrlThrow srUri
-    let req' = if T.null srMethod
+    let req' = if B.null srMethod
                    then req
-                   else req { method = T.encodeUtf8 srMethod }
-        req'' = if T.null srBody
+                   else req { method = srMethod }
+        req'' = if B.null srBody
                     then req'
-                    else req' { requestBody =
-                                    RequestBodyBS $ T.encodeUtf8 srBody }
+                    else req' { requestBody = RequestBodyBS srBody }
         req''' = if null srHeaders
                      then req''
-                     -- TODO: implement caching of frequent header values
-                     else req'' { requestHeaders =
-                                      map (mk . T.encodeUtf8 *** T.encodeUtf8)
-                                        srHeaders }
+                     else req'' { requestHeaders = srHeaders }
     responseBody <$> httpLbs req''' httpManager
 
 httpManager :: Manager
@@ -250,4 +249,27 @@
     readFromByteStringAsJSON @SubrequestConf
 
 ngxExportAsyncIOYY 'subrequest
+
+-- | Makes an HTTP request.
+--
+-- Behaves exactly as 'subrequest' except it parses Haskell terms representing
+-- /SubrequestConf/ with 'read'.
+--
+-- An example of a subrequest configuration:
+--
+-- > SubrequestConf { srMethod = "GET"
+-- >                , srUri = "http://127.0.0.1/subreq"}
+-- >                , srBody = ""
+-- >                , srHeaders = [("Header1", "Value1"), ("Header2", "Value2")]
+-- >                }
+--
+-- Notice that unlike JSON parsing, fields of /SubrequestConf/ are not
+-- omittable and must be listed in the order shown in the example.
+subrequestWithRead
+    :: ByteString       -- ^ Subrequest configuration
+    -> IO L.ByteString
+subrequestWithRead = maybe (throwIO SubrequestParseError) doSubrequest .
+    readFromByteString @SubrequestConf
+
+ngxExportAsyncIOYY 'subrequestWithRead
 
diff --git a/ngx-export-tools-extra.cabal b/ngx-export-tools-extra.cabal
--- a/ngx-export-tools-extra.cabal
+++ b/ngx-export-tools-extra.cabal
@@ -1,5 +1,5 @@
 name:                       ngx-export-tools-extra
-version:                    0.3.0.0
+version:                    0.3.1.0
 synopsis:                   More extra tools for Nginx haskell module
 description:                More extra tools for
         <https://github.com/lyokha/nginx-haskell-module Nginx haskell module>.
