diff --git a/README.lhs b/README.lhs
deleted file mode 100644
--- a/README.lhs
+++ /dev/null
@@ -1,60 +0,0 @@
-hspec-wai [![Build Status](https://travis-ci.org/hspec/hspec-wai.svg?branch=master)](https://travis-ci.org/hspec/hspec-wai)
-===========
-
-Helpers to test [WAI](http://www.yesodweb.com/book/web-application-interface)
-applications with [Hspec](http://hspec.github.io/)
-
-## Example
-
-~~~ {.haskell}
-{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}
-module Main (main) where
-
-import           Test.Hspec
-import           Test.Hspec.Wai
-import           Test.Hspec.Wai.JSON
-
-import           Network.Wai (Application)
-import qualified Web.Scotty as S
-import           Data.Aeson (Value(..), object, (.=))
-
-main :: IO ()
-main = hspec spec
-
-app :: IO Application
-app = S.scottyApp $ do
-  S.get "/" $ do
-    S.text "hello"
-    S.setHeader "Content-Type" "text/plain"
-
-  S.get "/some-json" $ do
-    S.json $ object ["foo" .= Number 23, "bar" .= Number 42]
-    S.setHeader "Content-Type" "application/json"
-
-spec :: Spec
-spec = with app $ do
-  describe "GET /" $ do
-    it "responds with 200" $ do
-      get "/" `shouldRespondWith` 200
-
-    it "responds with 'hello'" $ do
-      get "/" `shouldRespondWith` "hello"
-
-    it "responds with 200 / 'hello'" $ do
-      get "/" `shouldRespondWith` "hello" {matchStatus = 200}
-
-    it "has Content-Type: text/plain" $ do
-      get "/" `shouldRespondWith` 200 {matchHeaders = [("Content-Type", "text/plain")]}
-
-  describe "GET /some-json" $ do
-    it "responds with some JSON" $ do
-      get "/some-json" `shouldRespondWith` [json|{foo: 23, bar: 42}|]
-~~~
-
-## Contributing
-
-1. Fork it
-2. Create your feature branch (`git checkout -b my-new-feature`)
-3. Commit your changes (`git commit -am 'Add some feature'`)
-4. Push to the branch (`git push origin my-new-feature`)
-5. Create new Pull Request
diff --git a/hspec-wai.cabal b/hspec-wai.cabal
--- a/hspec-wai.cabal
+++ b/hspec-wai.cabal
@@ -1,5 +1,5 @@
 name:             hspec-wai
-version:          0.4.1
+version:          0.5.0
 license:          MIT
 license-file:     LICENSE
 copyright:        (c) 2012-2014 Fujimura Daisuke,
@@ -24,7 +24,6 @@
   exposed-modules:
       Test.Hspec.Wai
       Test.Hspec.Wai.Internal
-      Test.Hspec.Wai.JSON
   other-modules:
       Test.Hspec.Wai.Util
       Test.Hspec.Wai.Matcher
@@ -38,9 +37,6 @@
     , wai >= 3
     , wai-extra >= 3
     , hspec2
-    , template-haskell
-    , aeson
-    , aeson-qq >= 0.7.3
 
 test-suite spec
   type:
@@ -61,19 +57,3 @@
     , wai
     , wai-extra
     , hspec2
-
-test-suite README
-  type:
-      exitcode-stdio-1.0
-  ghc-options:
-      -Wall -pgmL markdown-unlit
-  main-is:
-      README.lhs
-  build-depends:
-      base == 4.*
-    , markdown-unlit
-    , hspec2
-    , hspec-wai
-    , aeson
-    , wai
-    , scotty
diff --git a/src/Test/Hspec/Wai.hs b/src/Test/Hspec/Wai.hs
--- a/src/Test/Hspec/Wai.hs
+++ b/src/Test/Hspec/Wai.hs
@@ -17,6 +17,8 @@
 -- * Matching on the response
 , shouldRespondWith
 , ResponseMatcher(..)
+, MatchHeader(..)
+, (<:>)
 
 -- * Helpers and re-exports
 , liftIO
@@ -103,5 +105,5 @@
 -- method, request path, headers and body.
 request :: Method -> ByteString -> [Header] -> LB.ByteString -> WaiSession SResponse
 request method path headers body = getApp >>= liftIO . runSession (Wai.srequest $ SRequest req body)
- where
-   req = setPath defaultRequest {requestMethod = method, requestHeaders = headers} path
+  where
+    req = setPath defaultRequest {requestMethod = method, requestHeaders = headers} path
diff --git a/src/Test/Hspec/Wai/Internal.hs b/src/Test/Hspec/Wai/Internal.hs
--- a/src/Test/Hspec/Wai/Internal.hs
+++ b/src/Test/Hspec/Wai/Internal.hs
@@ -7,6 +7,7 @@
 , WaiSession(..)
 , runWaiSession
 , getApp
+, formatHeader
 ) where
 
 import           Control.Applicative
@@ -16,6 +17,7 @@
 import           Network.Wai.Test hiding (request)
 import           Test.Hspec
 import           Test.Hspec.Core (Example (..))
+import           Test.Hspec.Wai.Util (formatHeader)
 
 -- | An expectation in the `WaiSession` monad.  Failing expectations are
 -- communicated through exceptions (similar to `Expectation` and
diff --git a/src/Test/Hspec/Wai/JSON.hs b/src/Test/Hspec/Wai/JSON.hs
deleted file mode 100644
--- a/src/Test/Hspec/Wai/JSON.hs
+++ /dev/null
@@ -1,56 +0,0 @@
-{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}
-module Test.Hspec.Wai.JSON (
--- $setup
-  json
-, FromValue(..)
-) where
-
-import           Test.Hspec.Wai
-import           Data.ByteString.Lazy (ByteString)
-import           Data.Aeson (Value, encode)
-import           Data.Aeson.QQ
-import           Language.Haskell.TH.Quote
-
--- $setup
--- The examples in this module assume that you have the @QuasiQuotes@ language
--- extension enabled and that "Data.ByteString.Lazy.Char8" is imported
--- qualified as @L@:
---
--- >>> :set -XQuasiQuotes
--- >>> import Data.ByteString.Lazy.Char8 as L
-
--- | A `QuasiQuoter` for constructing JSON values.
---
--- The constructed value is polymorph and unifies to instances of `FromValue`.
---
--- When used as a `ResponseMatcher` it matches a response with
---
---  * a status code of @200@
---
---  * a @Content-Type@ header with value @application/json@
---
---  * the specified JSON as response body
---
--- When used as a @ByteString@ it creates a ByteString from the specified JSON
--- that can be used as a request body for e.g. @POST@ and @PUT@ requests.
---
--- Example:
---
--- >>> L.putStrLn [json|[23, {foo: 42}]|]
--- [23,{"foo":42}]
-json :: QuasiQuoter
-json = QuasiQuoter {
-  quoteExp = \input -> [|fromValue $(quoteExp aesonQQ input)|]
-, quotePat = const $ error "No quotePat defined for Test.Hspec.Wai.JSON.json"
-, quoteType = const $ error "No quoteType defined for Test.Hspec.Wai.JSON.json"
-, quoteDec = const $ error "No quoteDec defined for Test.Hspec.Wai.JSON.json"
-}
-
-class FromValue a where
-  fromValue :: Value -> a
-
-instance FromValue ResponseMatcher where
-  fromValue v = ResponseMatcher 200 [("Content-Type", "application/json")] (Just . encode $ v)
-
-instance FromValue ByteString where
-  fromValue = encode
diff --git a/src/Test/Hspec/Wai/Matcher.hs b/src/Test/Hspec/Wai/Matcher.hs
--- a/src/Test/Hspec/Wai/Matcher.hs
+++ b/src/Test/Hspec/Wai/Matcher.hs
@@ -1,15 +1,18 @@
 {-# LANGUAGE ViewPatterns #-}
 module Test.Hspec.Wai.Matcher (
   ResponseMatcher(..)
+, MatchHeader(..)
+, (<:>)
 , match
 ) where
 
-
+import           Control.Applicative
 import           Control.Monad
+import           Data.Maybe
 import           Data.Monoid
-import           Data.Functor
 import           Data.String
 import           Data.Text.Lazy.Encoding (encodeUtf8)
+import           Data.ByteString (ByteString)
 import qualified Data.ByteString.Lazy as LB
 import           Network.HTTP.Types
 import           Network.Wai.Test
@@ -18,10 +21,12 @@
 
 data ResponseMatcher = ResponseMatcher {
   matchStatus :: Int
-, matchHeaders :: [Header]
+, matchHeaders :: [MatchHeader]
 , matchBody :: Maybe LB.ByteString
 }
 
+data MatchHeader = MatchHeader ([Header] -> Maybe String)
+
 instance IsString ResponseMatcher where
   fromString s = ResponseMatcher 200 [] (Just . encodeUtf8 . fromString $ s)
 
@@ -53,13 +58,17 @@
       , "  but got:  " ++ actual
       ]
 
-checkHeaders :: [Header] -> [Header] -> Maybe String
-checkHeaders actual expected = case filter (`notElem` actual) expected of
-  [] -> Nothing
-  missing ->
-    let msg
-          | length missing == 1 = "missing header:"
-          | otherwise = "missing headers:"
-    in Just $ unlines (msg : formatHeaders missing ++ "the actual headers were:" : formatHeaders actual)
+checkHeaders :: [Header] -> [MatchHeader] -> Maybe String
+checkHeaders headers m = case go m of
+    [] -> Nothing
+    xs -> Just (mconcat xs ++ "the actual headers were:\n" ++ unlines (map formatHeader headers))
   where
-    formatHeaders = map (("  " ++) . formatHeader)
+    go = catMaybes . map (\(MatchHeader p) -> p headers)
+
+(<:>) :: HeaderName -> ByteString -> MatchHeader
+name <:> value = MatchHeader $ \headers -> guard (header `notElem` headers) >> (Just . unlines) [
+    "missing header:"
+  , formatHeader header
+  ]
+  where
+    header = (name, value)
diff --git a/src/Test/Hspec/Wai/Util.hs b/src/Test/Hspec/Wai/Util.hs
--- a/src/Test/Hspec/Wai/Util.hs
+++ b/src/Test/Hspec/Wai/Util.hs
@@ -14,7 +14,7 @@
 import           Network.HTTP.Types
 
 formatHeader :: Header -> String
-formatHeader header@(name, value) = fromMaybe (show header) (safeToString $ B.concat [CI.original name, ": ", value])
+formatHeader header@(name, value) = "  " ++ fromMaybe (show header) (safeToString $ B.concat [CI.original name, ": ", value])
 
 safeToString :: ByteString -> Maybe String
 safeToString bs = do
