diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2014, Zalora South East Asia Pte Ltd
+Copyright (c) 2014-2016, Zalora South East Asia Pte Ltd, Servant Contributors
 
 All rights reserved.
 
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,2 @@
-import Distribution.Simple
+import           Distribution.Simple
 main = defaultMain
diff --git a/include/overlapping-compat.h b/include/overlapping-compat.h
new file mode 100644
--- /dev/null
+++ b/include/overlapping-compat.h
@@ -0,0 +1,8 @@
+#if __GLASGOW_HASKELL__ >= 710
+#define OVERLAPPABLE_ {-# OVERLAPPABLE #-}
+#define OVERLAPPING_  {-# OVERLAPPING #-}
+#else
+{-# LANGUAGE OverlappingInstances #-}
+#define OVERLAPPABLE_
+#define OVERLAPPING_
+#endif
diff --git a/servant.cabal b/servant.cabal
--- a/servant.cabal
+++ b/servant.cabal
@@ -1,5 +1,5 @@
 name:                servant
-version:             0.4.4.7
+version:             0.5
 synopsis:            A family of combinators for defining webservices APIs
 description:
   A family of combinators for defining webservices APIs and serving them
@@ -11,11 +11,12 @@
 Bug-reports:         http://github.com/haskell-servant/servant/issues
 license:             BSD3
 license-file:        LICENSE
-author:              Alp Mestanogullari, Sönke Hahn, Julian K. Arni
-maintainer:          alpmestan@gmail.com
-copyright:           2014 Zalora South East Asia Pte Ltd
+author:              Servant Contributors
+maintainer:          haskell-servant-maintainers@googlegroups.com
+copyright:           2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors
 category:            Web
 build-type:          Simple
+extra-source-files:  include/*.h
 cabal-version:       >=1.10
 tested-with:         GHC >= 7.8
 source-repository head
@@ -26,34 +27,39 @@
   exposed-modules:
     Servant.API
     Servant.API.Alternative
+    Servant.API.BasicAuth
     Servant.API.Capture
     Servant.API.ContentTypes
-    Servant.API.Delete
-    Servant.API.Get
+    Servant.API.Experimental.Auth
     Servant.API.Header
-    Servant.API.Patch
-    Servant.API.Post
-    Servant.API.Put
+    Servant.API.HttpVersion
+    Servant.API.Internal.Test.ComprehensiveAPI
+    Servant.API.IsSecure
     Servant.API.QueryParam
-    Servant.API.MatrixParam
     Servant.API.Raw
+    Servant.API.RemoteHost
     Servant.API.ReqBody
     Servant.API.ResponseHeaders
     Servant.API.Sub
-    Servant.Common.Text
+    Servant.API.Vault
+    Servant.API.Verbs
+    Servant.API.WithNamedContext
     Servant.Utils.Links
   build-depends:
-      base >=4.7 && <4.9
+      base >=4.7 && <5
+    , base-compat >= 0.9
     , aeson >= 0.7
     , attoparsec >= 0.12
     , bytestring == 0.10.*
     , bytestring-conversion == 0.3.*
     , case-insensitive >= 1.2
+    , http-api-data >= 0.1  && < 0.3
     , http-media >= 0.4 && < 0.7
     , http-types >= 0.8 && < 0.10
     , text >= 1 && < 2
     , string-conversions >= 0.3 && < 0.5
     , network-uri >= 2.6
+    , vault >= 0.3 && <0.4
   hs-source-dirs: src
   default-language: Haskell2010
   other-extensions: CPP
@@ -77,6 +83,7 @@
                   , TypeSynonymInstances
                   , UndecidableInstances
   ghc-options: -Wall
+  include-dirs: include
 
 test-suite spec
   type: exitcode-stdio-1.0
@@ -85,6 +92,10 @@
   default-language: Haskell2010
   hs-source-dirs: test
   main-is: Spec.hs
+  other-modules:
+      Servant.API.ContentTypesSpec
+      Servant.API.ResponseHeadersSpec
+      Servant.Utils.LinksSpec
   build-depends:
       base == 4.*
     , aeson
@@ -93,7 +104,6 @@
     , hspec == 2.*
     , QuickCheck
     , quickcheck-instances
-    , parsec
     , servant
     , string-conversions
     , text
@@ -111,3 +121,4 @@
  buildable: True
  default-language: Haskell2010
  ghc-options: -threaded
+ include-dirs: include
diff --git a/src/Servant/API.hs b/src/Servant/API.hs
--- a/src/Servant/API.hs
+++ b/src/Servant/API.hs
@@ -1,6 +1,3 @@
-{-# LANGUAGE TypeFamilies         #-}
-{-# LANGUAGE TypeOperators        #-}
-{-# LANGUAGE UndecidableInstances #-}
 module Servant.API (
 
   -- * Combinators
@@ -14,25 +11,27 @@
   -- | Capturing parts of the url path as parsed values: @'Capture'@
   module Servant.API.Header,
   -- | Retrieving specific headers from the request
+  module Servant.API.HttpVersion,
+  -- | Retrieving the HTTP version of the request
   module Servant.API.QueryParam,
   -- | Retrieving parameters from the query string of the 'URI': @'QueryParam'@
   module Servant.API.ReqBody,
   -- | Accessing the request body as a JSON-encoded type: @'ReqBody'@
-  module Servant.API.MatrixParam,
-  -- | Retrieving matrix parameters from the 'URI' segment: @'MatrixParam'@
+  module Servant.API.RemoteHost,
+  -- | Retrieving the IP of the client
+  module Servant.API.IsSecure,
+  -- | Is the request made through HTTPS?
+  module Servant.API.Vault,
+  -- | Access the location for arbitrary data to be shared by applications and middleware
+  module Servant.API.WithNamedContext,
+  -- | Access context entries in combinators in servant-server
 
   -- * Actual endpoints, distinguished by HTTP method
-  module Servant.API.Get,
-  -- | @GET@ requests
-  module Servant.API.Post,
-  -- | @POST@ requests
-  module Servant.API.Delete,
-  -- | @DELETE@ requests
-  module Servant.API.Put,
-  -- | @PUT@ requests
-  module Servant.API.Patch,
-  -- | @PATCH@ requests
+  module Servant.API.Verbs,
 
+  -- * Authentication
+  module Servant.API.BasicAuth,
+
   -- * Content Types
   module Servant.API.ContentTypes,
   -- | Serializing and deserializing types based on @Accept@ and
@@ -45,33 +44,36 @@
   module Servant.API.Raw,
   -- | Plugging in a wai 'Network.Wai.Application', serving directories
 
-  -- * FromText and ToText
-  module Servant.Common.Text,
-  -- | Classes and instances for types that can be converted to and from @Text@
+  -- * FromHttpApiData and ToHttpApiData
+  module Web.HttpApiData,
+  -- | Classes and instances for types that can be converted to and from HTTP API data.
 
+
+  -- * Experimental modules
+  module Servant.API.Experimental.Auth,
+  -- | General Authentication
+
   -- * Utilities
   module Servant.Utils.Links,
   -- | Type-safe internal URIs
   ) where
 
 import           Servant.API.Alternative     ((:<|>) (..))
+import           Servant.API.BasicAuth       (BasicAuth,BasicAuthData(..))
 import           Servant.API.Capture         (Capture)
 import           Servant.API.ContentTypes    (Accept (..), FormUrlEncoded,
                                               FromFormUrlEncoded (..), JSON,
-                                              MimeRender (..),
+                                              MimeRender (..), NoContent (NoContent),
                                               MimeUnrender (..), OctetStream,
                                               PlainText, ToFormUrlEncoded (..))
-import           Servant.API.Delete          (Delete)
-import           Servant.API.Get             (Get)
+import           Servant.API.Experimental.Auth (AuthProtect)
 import           Servant.API.Header          (Header (..))
-import           Servant.API.MatrixParam     (MatrixFlag, MatrixParam,
-                                              MatrixParams)
-import           Servant.API.Patch           (Patch)
-import           Servant.API.Post            (Post)
-import           Servant.API.Put             (Put)
+import           Servant.API.HttpVersion     (HttpVersion (..))
+import           Servant.API.IsSecure        (IsSecure (..))
 import           Servant.API.QueryParam      (QueryFlag, QueryParam,
                                               QueryParams)
 import           Servant.API.Raw             (Raw)
+import           Servant.API.RemoteHost      (RemoteHost)
 import           Servant.API.ReqBody         (ReqBody)
 import           Servant.API.ResponseHeaders (AddHeader (addHeader),
                                               BuildHeadersTo (buildHeadersTo),
@@ -79,7 +81,27 @@
                                               HList (..), Headers (..),
                                               getHeadersHList, getResponse)
 import           Servant.API.Sub             ((:>))
-import           Servant.Common.Text         (FromText (..), ToText (..))
+import           Servant.API.Vault           (Vault)
+import           Servant.API.Verbs           (PostCreated, Delete, DeleteAccepted,
+                                              DeleteNoContent,
+                                              DeleteNonAuthoritative, Get,
+                                              GetAccepted, GetNoContent,
+                                              GetNonAuthoritative,
+                                              GetPartialContent,
+                                              GetResetContent,
+                                              Patch,
+                                              PatchAccepted, PatchNoContent,
+                                              PatchNoContent,
+                                              PatchNonAuthoritative, Post,
+                                              PostAccepted, PostNoContent,
+                                              PostNonAuthoritative,
+                                              PostResetContent, Put,
+                                              PutAccepted, PutNoContent,
+                                              PutNoContent, PutNonAuthoritative,
+                                              ReflectMethod (reflectMethod),
+                                              Verb, StdMethod(..))
+import           Servant.API.WithNamedContext (WithNamedContext)
 import           Servant.Utils.Links         (HasLink (..), IsElem, IsElem',
                                               URI (..), safeLink)
-
+import           Web.HttpApiData             (FromHttpApiData (..),
+                                              ToHttpApiData (..))
diff --git a/src/Servant/API/Alternative.hs b/src/Servant/API/Alternative.hs
--- a/src/Servant/API/Alternative.hs
+++ b/src/Servant/API/Alternative.hs
@@ -1,13 +1,18 @@
 {-# LANGUAGE CPP                #-}
 {-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor      #-}
+#if !MIN_VERSION_base(4,8,0)
+{-# LANGUAGE DeriveFoldable     #-}
+#endif
+{-# LANGUAGE DeriveTraversable  #-}
 {-# LANGUAGE TypeOperators      #-}
 {-# OPTIONS_HADDOCK not-home    #-}
 module Servant.API.Alternative ((:<|>)(..)) where
 
-#if !MIN_VERSION_base(4,8,0)
-import           Data.Monoid   (Monoid (..))
-#endif
-import           Data.Typeable (Typeable)
+import           Data.Typeable    (Typeable)
+import           Prelude ()
+import           Prelude.Compat
+
 -- | Union of two APIs, first takes precedence in case of overlap.
 --
 -- Example:
@@ -17,7 +22,7 @@
 --        :<|> "books" :> ReqBody '[JSON] Book :> Post '[JSON] () -- POST /books
 -- :}
 data a :<|> b = a :<|> b
-    deriving (Typeable, Eq, Show)
+    deriving (Typeable, Eq, Show, Functor, Traversable, Foldable, Bounded)
 infixr 8 :<|>
 
 instance (Monoid a, Monoid b) => Monoid (a :<|> b) where
diff --git a/src/Servant/API/BasicAuth.hs b/src/Servant/API/BasicAuth.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/API/BasicAuth.hs
@@ -0,0 +1,29 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE KindSignatures     #-}
+{-# LANGUAGE PolyKinds          #-}
+module Servant.API.BasicAuth where
+
+import           Data.ByteString (ByteString)
+import           Data.Typeable (Typeable)
+import           GHC.TypeLits  (Symbol)
+
+
+-- | Combinator for <https://tools.ietf.org/html/rfc2617#section-2 Basic Access Authentication>.
+--
+-- *IMPORTANT*: Only use Basic Auth over HTTPS! Credentials are not hashed or
+-- encrypted. Note also that because the same credentials are sent on every
+-- request, Basic Auth is not as secure as some alternatives. Further, the
+-- implementation in servant-server does not protect against some types of
+-- timing attacks.
+--
+-- In Basic Auth, username and password are base64-encoded and transmitted via
+-- the @Authorization@ header. Handshakes are not required, making it
+-- relatively efficient.
+data BasicAuth (realm :: Symbol) (userData :: *)
+  deriving (Typeable)
+
+-- | A simple datatype to hold data required to decorate a request
+data BasicAuthData = BasicAuthData { basicAuthUsername :: !ByteString
+                                   , basicAuthPassword :: !ByteString
+                                   }
diff --git a/src/Servant/API/ContentTypes.hs b/src/Servant/API/ContentTypes.hs
--- a/src/Servant/API/ContentTypes.hs
+++ b/src/Servant/API/ContentTypes.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE ConstraintKinds       #-}
 {-# LANGUAGE DataKinds             #-}
 {-# LANGUAGE DeriveDataTypeable    #-}
+{-# LANGUAGE DeriveGeneric         #-}
 {-# LANGUAGE FlexibleInstances     #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE OverloadedStrings     #-}
@@ -12,6 +13,8 @@
 {-# LANGUAGE UndecidableInstances  #-}
 {-# OPTIONS_HADDOCK not-home       #-}
 
+#include "overlapping-compat.h"
+
 -- | A collection of basic Content-Types (also known as Internet Media
 -- Types, or MIME types). Additionally, this module provides classes that
 -- encapsulate how to serialize or deserialize values to or from
@@ -19,7 +22,7 @@
 --
 -- Content-Types are used in `ReqBody` and the method combinators:
 --
--- >>> type MyEndpoint = ReqBody '[JSON, PlainText] Book :> Get '[JSON, PlainText] :> Book
+-- >>> type MyEndpoint = ReqBody '[JSON, PlainText] Book :> Get '[JSON, PlainText] Book
 --
 -- Meaning the endpoint accepts requests of Content-Type @application/json@
 -- or @text/plain;charset-utf8@, and returns data in either one of those
@@ -53,25 +56,25 @@
     , MimeRender(..)
     , MimeUnrender(..)
 
+    -- * NoContent
+    , NoContent(..)
+
     -- * Internal
     , AcceptHeader(..)
     , AllCTRender(..)
     , AllCTUnrender(..)
+    , AllMime(..)
     , AllMimeRender(..)
     , AllMimeUnrender(..)
     , FromFormUrlEncoded(..)
     , ToFormUrlEncoded(..)
-    , IsNonEmpty
     , eitherDecodeLenient
+    , canHandleAcceptH
     ) where
 
-#if !MIN_VERSION_base(4,8,0)
-import           Control.Applicative              ((*>), (<*))
-#endif
 import           Control.Arrow                    (left)
-import           Control.Monad
-import           Data.Aeson                       (FromJSON, ToJSON, encode,
-                                                   parseJSON)
+import           Control.Monad.Compat
+import           Data.Aeson                       (FromJSON(..), ToJSON(..), encode)
 import           Data.Aeson.Parser                (value)
 import           Data.Aeson.Types                 (parseEither)
 import           Data.Attoparsec.ByteString.Char8 (endOfInput, parseOnly,
@@ -80,17 +83,21 @@
 import           Data.ByteString.Lazy             (ByteString, fromStrict,
                                                    toStrict)
 import qualified Data.ByteString.Lazy             as B
-import           Data.Monoid
+import qualified Data.ByteString.Lazy.Char8       as BC
+import           Data.Maybe                       (isJust)
+import           Data.Monoid.Compat
 import           Data.String.Conversions          (cs)
 import qualified Data.Text                        as TextS
 import qualified Data.Text.Encoding               as TextS
 import qualified Data.Text.Lazy                   as TextL
 import qualified Data.Text.Lazy.Encoding          as TextL
 import           Data.Typeable
-import           GHC.Exts                         (Constraint)
+import           GHC.Generics                     (Generic)
 import qualified Network.HTTP.Media               as M
 import           Network.URI                      (escapeURIString,
                                                    isUnreserved, unEscapeString)
+import           Prelude                          ()
+import           Prelude.Compat
 
 -- * Provided content types
 data JSON deriving Typeable
@@ -133,7 +140,7 @@
     contentType _ = "application" M.// "octet-stream"
 
 newtype AcceptHeader = AcceptHeader BS.ByteString
-    deriving (Eq, Show)
+    deriving (Eq, Show, Read, Typeable, Generic)
 
 -- * Render (serializing)
 
@@ -155,20 +162,19 @@
 class Accept ctype => MimeRender ctype a where
     mimeRender  :: Proxy ctype -> a -> ByteString
 
-class AllCTRender (list :: [*]) a where
+class (AllMime list) => AllCTRender (list :: [*]) a where
     -- If the Accept header can be matched, returns (Just) a tuple of the
     -- Content-Type and response (serialization of @a@ into the appropriate
     -- mimetype).
     handleAcceptH :: Proxy list -> AcceptHeader -> a -> Maybe (ByteString, ByteString)
 
-instance ( AllMimeRender ctyps a, IsNonEmpty ctyps
-         ) => AllCTRender ctyps a where
+instance OVERLAPPABLE_
+         (AllMimeRender (ct ': cts) a) => AllCTRender (ct ': cts) a where
     handleAcceptH _ (AcceptHeader accept) val = M.mapAcceptMedia lkup accept
-      where pctyps = Proxy :: Proxy ctyps
+      where pctyps = Proxy :: Proxy (ct ': cts)
             amrs = allMimeRender pctyps val
             lkup = fmap (\(a,b) -> (a, (fromStrict $ M.renderHeader a, b))) amrs
 
-
 --------------------------------------------------------------------------
 -- * Unrender
 
@@ -196,34 +202,47 @@
 class Accept ctype => MimeUnrender ctype a where
     mimeUnrender :: Proxy ctype -> ByteString -> Either String a
 
-class (IsNonEmpty list) => AllCTUnrender (list :: [*]) a where
+class AllCTUnrender (list :: [*]) a where
     handleCTypeH :: Proxy list
                  -> ByteString     -- Content-Type header
                  -> ByteString     -- Request body
                  -> Maybe (Either String a)
 
-instance ( AllMimeUnrender ctyps a, IsNonEmpty ctyps
-         ) => AllCTUnrender ctyps a where
+instance ( AllMimeUnrender ctyps a ) => AllCTUnrender ctyps a where
     handleCTypeH _ ctypeH body = M.mapContentMedia lkup (cs ctypeH)
       where lkup = allMimeUnrender (Proxy :: Proxy ctyps) body
 
 --------------------------------------------------------------------------
 -- * Utils (Internal)
 
+class AllMime (list :: [*]) where
+    allMime :: Proxy list -> [M.MediaType]
 
+instance AllMime '[] where
+    allMime _ = []
+
+instance (Accept ctyp, AllMime ctyps) => AllMime (ctyp ': ctyps) where
+    allMime _ = (contentType pctyp):allMime pctyps
+      where pctyp  = Proxy :: Proxy ctyp
+            pctyps = Proxy :: Proxy ctyps
+
+canHandleAcceptH :: AllMime list => Proxy list -> AcceptHeader -> Bool
+canHandleAcceptH p (AcceptHeader h ) = isJust $ M.matchAccept (allMime p) h
+
 --------------------------------------------------------------------------
 -- Check that all elements of list are instances of MimeRender
 --------------------------------------------------------------------------
-class AllMimeRender (list :: [*]) a where
+class (AllMime list) => AllMimeRender (list :: [*]) a where
     allMimeRender :: Proxy list
                   -> a                              -- value to serialize
                   -> [(M.MediaType, ByteString)]    -- content-types/response pairs
 
-instance ( MimeRender ctyp a ) => AllMimeRender '[ctyp] a where
+instance OVERLAPPABLE_ ( MimeRender ctyp a ) => AllMimeRender '[ctyp] a where
     allMimeRender _ a = [(contentType pctyp, mimeRender pctyp a)]
         where pctyp = Proxy :: Proxy ctyp
 
-instance ( MimeRender ctyp a
+instance OVERLAPPABLE_
+         ( MimeRender ctyp a
          , AllMimeRender (ctyp' ': ctyps) a
          ) => AllMimeRender (ctyp ': ctyp' ': ctyps) a where
     allMimeRender _ a = (contentType pctyp, mimeRender pctyp a)
@@ -232,13 +251,22 @@
               pctyps = Proxy :: Proxy (ctyp' ': ctyps)
 
 
-instance AllMimeRender '[] a where
-    allMimeRender _ _ = []
+-- Ideally we would like to declare a 'MimeRender a NoContent' instance, and
+-- then this would be taken care of. However there is no more specific instance
+-- between that and 'MimeRender JSON a', so we do this instead
+instance OVERLAPPING_ ( Accept ctyp ) => AllMimeRender '[ctyp] NoContent where
+    allMimeRender _ _ = [(contentType pctyp, "")]
+      where pctyp = Proxy :: Proxy ctyp
 
+instance OVERLAPPING_
+         ( AllMime (ctyp ': ctyp' ': ctyps)
+         ) => AllMimeRender (ctyp ': ctyp' ': ctyps) NoContent where
+    allMimeRender p _ = zip (allMime p) (repeat "")
+
 --------------------------------------------------------------------------
 -- Check that all elements of list are instances of MimeUnrender
 --------------------------------------------------------------------------
-class AllMimeUnrender (list :: [*]) a where
+class (AllMime list) => AllMimeUnrender (list :: [*]) a where
     allMimeUnrender :: Proxy list
                     -> ByteString
                     -> [(M.MediaType, Either String a)]
@@ -254,21 +282,19 @@
         where pctyp = Proxy :: Proxy ctyp
               pctyps = Proxy :: Proxy ctyps
 
-type family IsNonEmpty (list :: [*]) :: Constraint where
-    IsNonEmpty (x ': xs)   = ()
-
-
 --------------------------------------------------------------------------
 -- * MimeRender Instances
 
 -- | `encode`
-instance ToJSON a => MimeRender JSON a where
+instance OVERLAPPABLE_
+         ToJSON a => MimeRender JSON a where
     mimeRender _ = encode
 
 -- | @encodeFormUrlEncoded . toFormUrlEncoded@
 -- Note that the @mimeUnrender p (mimeRender p x) == Right x@ law only
 -- holds if every element of x is non-null (i.e., not @("", "")@)
-instance ToFormUrlEncoded a => MimeRender FormUrlEncoded a where
+instance OVERLAPPABLE_
+         ToFormUrlEncoded a => MimeRender FormUrlEncoded a where
     mimeRender _ = encodeFormUrlEncoded . toFormUrlEncoded
 
 -- | `TextL.encodeUtf8`
@@ -279,6 +305,10 @@
 instance MimeRender PlainText TextS.Text where
     mimeRender _ = fromStrict . TextS.encodeUtf8
 
+-- | @BC.pack@
+instance MimeRender PlainText String where
+    mimeRender _ = BC.pack
+
 -- | @id@
 instance MimeRender OctetStream ByteString where
     mimeRender _ = id
@@ -287,7 +317,11 @@
 instance MimeRender OctetStream BS.ByteString where
     mimeRender _ = fromStrict
 
+-- | A type for responses without content-body.
+data NoContent = NoContent
+  deriving (Show, Eq, Read)
 
+
 --------------------------------------------------------------------------
 -- * MimeUnrender Instances
 
@@ -327,6 +361,10 @@
 -- | @left show . TextS.decodeUtf8' . toStrict@
 instance MimeUnrender PlainText TextS.Text where
     mimeUnrender _ = left show . TextS.decodeUtf8' . toStrict
+
+-- | @Right . BC.unpack@
+instance MimeUnrender PlainText String where
+    mimeUnrender _ = Right . BC.unpack
 
 -- | @Right . id@
 instance MimeUnrender OctetStream ByteString where
diff --git a/src/Servant/API/Delete.hs b/src/Servant/API/Delete.hs
deleted file mode 100644
--- a/src/Servant/API/Delete.hs
+++ /dev/null
@@ -1,24 +0,0 @@
-{-# LANGUAGE DataKinds          #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE KindSignatures     #-}
-{-# OPTIONS_HADDOCK not-home    #-}
-module Servant.API.Delete (Delete) where
-
-import Data.Typeable ( Typeable )
-
--- | Combinator for DELETE requests.
---
--- Example:
---
--- >>>            -- DELETE /books/:isbn
--- >>> type MyApi = "books" :> Capture "isbn" Text :> Delete
-data Delete (contentTypes :: [*]) a
-  deriving Typeable
-
-
--- $setup
--- >>> import Servant.API
--- >>> import Data.Aeson
--- >>> import Data.Text
--- >>> data Book
--- >>> instance ToJSON Book where { toJSON = undefined }
diff --git a/src/Servant/API/Experimental/Auth.hs b/src/Servant/API/Experimental/Auth.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/API/Experimental/Auth.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE KindSignatures     #-}
+{-# LANGUAGE PolyKinds          #-}
+module Servant.API.Experimental.Auth where
+
+import           Data.Typeable (Typeable)
+
+-- | A generalized Authentication combinator. Use this if you have a
+-- non-standard authentication technique.
+--
+-- NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE.
+data AuthProtect (tag :: k) deriving (Typeable)
+
diff --git a/src/Servant/API/Get.hs b/src/Servant/API/Get.hs
deleted file mode 100644
--- a/src/Servant/API/Get.hs
+++ /dev/null
@@ -1,22 +0,0 @@
-{-# LANGUAGE DataKinds          #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE KindSignatures     #-}
-{-# OPTIONS_HADDOCK not-home    #-}
-module Servant.API.Get (Get) where
-
-import           Data.Typeable (Typeable)
-
--- | Endpoint for simple GET requests. Serves the result as JSON.
---
--- Example:
---
--- >>> type MyApi = "books" :> Get '[JSON] [Book]
-data Get (contentTypes :: [*]) a
-  deriving Typeable
-
--- $setup
--- >>> import Servant.API
--- >>> import Data.Aeson
--- >>> import Data.Text
--- >>> data Book
--- >>> instance ToJSON Book where { toJSON = undefined }
diff --git a/src/Servant/API/Header.hs b/src/Servant/API/Header.hs
--- a/src/Servant/API/Header.hs
+++ b/src/Servant/API/Header.hs
@@ -23,7 +23,6 @@
 
 -- $setup
 -- >>> import Servant.API
--- >>> import Servant.Common.Text
 -- >>> import Data.Aeson
 -- >>> import Data.Text
 -- >>> data Book
diff --git a/src/Servant/API/HttpVersion.hs b/src/Servant/API/HttpVersion.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/API/HttpVersion.hs
@@ -0,0 +1,19 @@
+module Servant.API.HttpVersion
+  ( -- $httpversion
+    HttpVersion(..)
+  ) where
+
+import           Network.HTTP.Types (HttpVersion (..))
+
+-- $httpversion
+--
+-- | You can directly use the 'HttpVersion' type from @Network.HTTP.Types@
+--   if your request handlers need it to compute a response. This would
+--   make the request handlers take an argument of type 'HttpVersion'.
+--
+-- Example:
+--
+-- >>> type API = HttpVersion :> Get '[JSON] String
+
+-- $setup
+-- >>> import Servant.API
diff --git a/src/Servant/API/Internal/Test/ComprehensiveAPI.hs b/src/Servant/API/Internal/Test/ComprehensiveAPI.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/API/Internal/Test/ComprehensiveAPI.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeOperators #-}
+
+-- | This is a module containing an API with all `Servant.API` combinators. It
+-- is used for testing only (in particular, checking that instances exist for
+-- the core servant classes for each combinator), and should not be imported.
+module Servant.API.Internal.Test.ComprehensiveAPI where
+
+import           Data.Proxy
+
+import           Servant.API
+
+type GET = Get '[JSON] ()
+
+type ComprehensiveAPI =
+  GET :<|>
+  Get '[JSON] Int :<|>
+  Capture "foo" Int :> GET :<|>
+  Header "foo" Int :> GET :<|>
+  HttpVersion :> GET :<|>
+  IsSecure :> GET :<|>
+  QueryParam "foo" Int :> GET :<|>
+  QueryParams "foo" Int :> GET :<|>
+  QueryFlag "foo" :> GET :<|>
+-- Raw :<|>
+  RemoteHost :> GET :<|>
+  ReqBody '[JSON] Int :> GET :<|>
+  Get '[JSON] (Headers '[Header "foo" Int] ()) :<|>
+  "foo" :> GET :<|>
+  Vault :> GET :<|>
+  Verb 'POST 204 '[JSON] () :<|>
+  Verb 'POST 204 '[JSON] Int :<|>
+  WithNamedContext "foo" '[] GET
+
+comprehensiveAPI :: Proxy ComprehensiveAPI
+comprehensiveAPI = Proxy
diff --git a/src/Servant/API/IsSecure.hs b/src/Servant/API/IsSecure.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/API/IsSecure.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+module Servant.API.IsSecure
+  ( -- $issecure
+    IsSecure(..)
+  ) where
+
+import           Data.Typeable
+
+-- | Was this request made over an SSL connection?
+--
+-- Note that this value will not tell you if the client originally
+-- made this request over SSL, but rather whether the current
+-- connection is SSL. The distinction lies with reverse proxies.
+-- In many cases, the client will connect to a load balancer over SSL,
+-- but connect to the WAI handler without SSL. In such a case,
+-- the handlers would get 'NotSecure', but from a user perspective,
+-- there is a secure connection.
+data IsSecure = Secure    -- ^ the connection to the server
+                          --   is secure (HTTPS)
+              | NotSecure -- ^ the connection to the server
+                          --   is not secure (HTTP)
+  deriving Typeable
+
+-- $issecure
+--
+-- | Use 'IsSecure' whenever your request handlers need to know whether
+--   the connection to the server is secure or not.
+--   This would make the request handlers receive an argument of type 'IsSecure',
+--   whose value can be one of 'Secure' (HTTPS) or 'NotSecure' (HTTP).
+--
+-- Example:
+--
+-- >>> type API = "sensitive-data" :> IsSecure :> Get '[JSON] NationSecrets
+
+-- $setup
+-- >>> import Servant.API
+-- >>> data NationSecrets
diff --git a/src/Servant/API/MatrixParam.hs b/src/Servant/API/MatrixParam.hs
deleted file mode 100644
--- a/src/Servant/API/MatrixParam.hs
+++ /dev/null
@@ -1,51 +0,0 @@
-{-# LANGUAGE DataKinds          #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE PolyKinds          #-}
-{-# OPTIONS_HADDOCK not-home    #-}
-module Servant.API.MatrixParam (MatrixFlag, MatrixParam, MatrixParams) where
-
-import           Data.Typeable (Typeable)
-import           GHC.TypeLits  (Symbol)
--- | Lookup the value associated to the @sym@ matrix string parameter
--- and try to extract it as a value of type @a@.
---
--- Example:
---
--- >>> -- /books;author=<author name>
--- >>> type MyApi = "books" :> MatrixParam "author" Text :> Get '[JSON] [Book]
-data MatrixParam (sym :: Symbol) a
-    deriving (Typeable)
-
--- | Lookup the values associated to the @sym@ matrix string parameter
--- and try to extract it as a value of type @[a]@. This is typically
--- meant to support matrix string parameters of the form
--- @param[]=val1;param[]=val2@ and so on. Note that servant doesn't actually
--- require the @[]@s and will fetch the values just fine with
--- @param=val1;param=val2@, too.
---
--- Example:
---
--- >>> -- /books;authors[]=<author1>;authors[]=<author2>;...
--- >>> type MyApi = "books" :> MatrixParams "authors" Text :> Get '[JSON] [Book]
-data MatrixParams (sym :: Symbol) a
-    deriving (Typeable)
-
--- | Lookup a potentially value-less matrix string parameter
--- with boolean semantics. If the param @sym@ is there without any value,
--- or if it's there with value "true" or "1", it's interpreted as 'True'.
--- Otherwise, it's interpreted as 'False'.
---
--- Example:
---
--- >>> -- /books;published
--- >>> type MyApi = "books" :> MatrixFlag "published" :> Get '[JSON] [Book]
-data MatrixFlag (sym :: Symbol)
-    deriving (Typeable)
-
-
--- $setup
--- >>> import Servant.API
--- >>> import Data.Aeson
--- >>> import Data.Text
--- >>> data Book
--- >>> instance ToJSON Book where { toJSON = undefined }
diff --git a/src/Servant/API/Patch.hs b/src/Servant/API/Patch.hs
deleted file mode 100644
--- a/src/Servant/API/Patch.hs
+++ /dev/null
@@ -1,29 +0,0 @@
-{-# LANGUAGE DataKinds          #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE KindSignatures     #-}
-{-# OPTIONS_HADDOCK not-home    #-}
-module Servant.API.Patch (Patch) where
-
-import           Data.Typeable (Typeable)
-
--- | Endpoint for PATCH requests. The type variable represents the type of the
--- response body (not the request body, use 'Servant.API.ReqBody.ReqBody' for
--- that).
---
--- If the HTTP response is empty, only () is supported.
---
--- Example:
---
--- >>>            -- PATCH /books
--- >>>            -- with a JSON encoded Book as the request body
--- >>>            -- returning the just-created Book
--- >>> type MyApi = "books" :> ReqBody '[JSON] Book :> Patch '[JSON] Book
-data Patch (contentTypes :: [*]) a
-  deriving Typeable
-
--- $setup
--- >>> import Servant.API
--- >>> import Data.Aeson
--- >>> import Data.Text
--- >>> data Book
--- >>> instance ToJSON Book where { toJSON = undefined }
diff --git a/src/Servant/API/Post.hs b/src/Servant/API/Post.hs
deleted file mode 100644
--- a/src/Servant/API/Post.hs
+++ /dev/null
@@ -1,27 +0,0 @@
-{-# LANGUAGE DataKinds          #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE KindSignatures     #-}
-{-# OPTIONS_HADDOCK not-home    #-}
-module Servant.API.Post (Post) where
-
-import           Data.Typeable (Typeable)
-
--- | Endpoint for POST requests. The type variable represents the type of the
--- response body (not the request body, use 'Servant.API.ReqBody.ReqBody' for
--- that).
---
--- Example:
---
--- >>>            -- POST /books
--- >>>            -- with a JSON encoded Book as the request body
--- >>>            -- returning the just-created Book
--- >>> type MyApi = "books" :> ReqBody '[JSON] Book :> Post '[JSON] Book
-data Post (contentTypes :: [*]) a
-  deriving Typeable
-
--- $setup
--- >>> import Servant.API
--- >>> import Data.Aeson
--- >>> import Data.Text
--- >>> data Book
--- >>> instance ToJSON Book where { toJSON = undefined }
diff --git a/src/Servant/API/Put.hs b/src/Servant/API/Put.hs
deleted file mode 100644
--- a/src/Servant/API/Put.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-{-# LANGUAGE DataKinds          #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE KindSignatures     #-}
-{-# OPTIONS_HADDOCK not-home    #-}
-module Servant.API.Put (Put) where
-
-import Data.Typeable ( Typeable )
-
--- | Endpoint for PUT requests, usually used to update a ressource.
--- The type @a@ is the type of the response body that's returned.
---
--- Example:
---
--- >>> -- PUT /books/:isbn
--- >>> -- with a Book as request body, returning the updated Book
--- >>> type MyApi = "books" :> Capture "isbn" Text :> ReqBody '[JSON] Book :> Put '[JSON] Book
-data Put (contentTypes :: [*]) a
-  deriving Typeable
-
--- $setup
--- >>> import Servant.API
--- >>> import Data.Aeson
--- >>> import Data.Text
--- >>> data Book
--- >>> instance ToJSON Book where { toJSON = undefined }
diff --git a/src/Servant/API/Raw.hs b/src/Servant/API/Raw.hs
--- a/src/Servant/API/Raw.hs
+++ b/src/Servant/API/Raw.hs
@@ -2,7 +2,7 @@
 {-# OPTIONS_HADDOCK not-home    #-}
 module Servant.API.Raw where
 
-import Data.Typeable (Typeable)
+import           Data.Typeable (Typeable)
 -- | Endpoint for plugging in your own Wai 'Application's.
 --
 -- The given 'Application' will get the request as received by the server, potentially with
diff --git a/src/Servant/API/RemoteHost.hs b/src/Servant/API/RemoteHost.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/API/RemoteHost.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+module Servant.API.RemoteHost
+  ( -- $remotehost
+    RemoteHost
+  ) where
+
+import           Data.Typeable
+
+-- | Provides access to the host or IP address
+--   from which the HTTP request was sent.
+data RemoteHost deriving Typeable
+
+-- $remotehost
+--
+-- | Use 'RemoteHost' whenever your request handlers need the host or IP address
+--   from which the client issued the HTTP request. The corresponding handlers
+--   receive arguments of type @SockAddr@ (from @Network.Socket@).
+--
+-- Example:
+--
+-- >>> -- POST /record-ip
+-- >>> type API = "record-ip" :> RemoteHost :> Post '[] ()
+
+-- $setup
+-- >>> import Servant.API
diff --git a/src/Servant/API/ReqBody.hs b/src/Servant/API/ReqBody.hs
--- a/src/Servant/API/ReqBody.hs
+++ b/src/Servant/API/ReqBody.hs
@@ -16,7 +16,6 @@
 
 -- $setup
 -- >>> import Servant.API
--- >>> import Servant.Common.Text
 -- >>> import Data.Aeson
 -- >>> import Data.Text
 -- >>> data Book
diff --git a/src/Servant/API/ResponseHeaders.hs b/src/Servant/API/ResponseHeaders.hs
--- a/src/Servant/API/ResponseHeaders.hs
+++ b/src/Servant/API/ResponseHeaders.hs
@@ -12,11 +12,9 @@
 {-# LANGUAGE TypeFamilies           #-}
 {-# LANGUAGE TypeOperators          #-}
 {-# LANGUAGE UndecidableInstances   #-}
-#if !MIN_VERSION_base(4,8,0)
-{-# LANGUAGE OverlappingInstances   #-}
-#endif
 {-# OPTIONS_HADDOCK not-home        #-}
 
+#include "overlapping-compat.h"
 -- | This module provides facilities for adding headers to a response.
 --
 -- >>> let headerVal = addHeader "some-url" 5 :: Headers '[Header "Location" String] Int
@@ -32,9 +30,6 @@
     , HList(..)
     ) where
 
-#if !MIN_VERSION_base(4,8,0)
-import           Control.Applicative         ((<$>))
-#endif
 import           Data.ByteString.Char8       as BS (pack, unlines, init)
 import           Data.ByteString.Conversion  (ToByteString, toByteString',
                                               FromByteString, fromByteString)
@@ -44,6 +39,8 @@
 import qualified Network.HTTP.Types.Header   as HTTP
 
 import           Servant.API.Header          (Header (..))
+import           Prelude                     ()
+import           Prelude.Compat
 
 -- | Response Header objects. You should never need to construct one directly.
 -- Instead, use 'addHeader'.
@@ -68,19 +65,12 @@
     -- the values are interspersed with commas before deserialization (see
     -- <http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 RFC2616 Sec 4.2>)
 
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-         BuildHeadersTo '[] where
+instance OVERLAPPING_ BuildHeadersTo '[] where
     buildHeadersTo _ = HNil
 
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPABLE #-}
-#endif
-         ( FromByteString v, BuildHeadersTo xs, KnownSymbol h, Contains h xs ~ 'False
-         ) => BuildHeadersTo ((Header h v) ': xs) where
+instance OVERLAPPABLE_ ( FromByteString v, BuildHeadersTo xs, KnownSymbol h
+                       , Contains h xs ~ 'False)
+         => BuildHeadersTo ((Header h v) ': xs) where
     buildHeadersTo headers =
       let wantedHeader = CI.mk . pack $ symbolVal (Proxy :: Proxy h)
           matching = snd <$> filter (\(h, _) -> h == wantedHeader) headers
@@ -96,38 +86,22 @@
 class GetHeaders ls where
     getHeaders :: ls -> [HTTP.Header]
 
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-         GetHeaders (HList '[]) where
+instance OVERLAPPING_ GetHeaders (HList '[]) where
     getHeaders _ = []
 
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPABLE #-}
-#endif
-         ( KnownSymbol h, ToByteString x, GetHeaders (HList xs)
-         ) => GetHeaders (HList (Header h x ': xs)) where
+instance OVERLAPPABLE_ ( KnownSymbol h, ToByteString x, GetHeaders (HList xs))
+         => GetHeaders (HList (Header h x ': xs)) where
     getHeaders hdrs = case hdrs of
         Header val `HCons` rest -> (headerName , toByteString' val):getHeaders rest
         UndecodableHeader h `HCons` rest -> (headerName,  h) : getHeaders rest
         MissingHeader `HCons` rest -> getHeaders rest
       where headerName = CI.mk . pack $ symbolVal (Proxy :: Proxy h)
 
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-         GetHeaders (Headers '[] a) where
+instance OVERLAPPING_ GetHeaders (Headers '[] a) where
     getHeaders _ = []
 
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPABLE #-}
-#endif
-         ( KnownSymbol h, GetHeaders (HList rest), ToByteString v
-         ) => GetHeaders (Headers (Header h v ': rest) a) where
+instance OVERLAPPABLE_ ( KnownSymbol h, GetHeaders (HList rest), ToByteString v)
+         => GetHeaders (Headers (Header h v ': rest) a) where
     getHeaders hs = getHeaders $ getHeadersHList hs
 
 -- * Adding
@@ -138,21 +112,13 @@
   addHeader :: v -> orig -> new  -- ^ N.B.: The same header can't be added multiple times
 
 
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-         ( KnownSymbol h, ToByteString v, Contains h (fst ': rest) ~ 'False
-         ) => AddHeader h v (Headers (fst ': rest)  a) (Headers (Header h v  ': fst ': rest) a) where
+instance OVERLAPPING_ ( KnownSymbol h, ToByteString v, Contains h (fst ': rest) ~ 'False)
+         => AddHeader h v (Headers (fst ': rest)  a) (Headers (Header h v  ': fst ': rest) a) where
     addHeader a (Headers resp heads) = Headers resp (HCons (Header a) heads)
 
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPABLE #-}
-#endif
-         ( KnownSymbol h, ToByteString v
-         , new ~ (Headers '[Header h v] a)
-         ) => AddHeader h v a new where
+instance OVERLAPPABLE_ ( KnownSymbol h, ToByteString v
+                       , new ~ (Headers '[Header h v] a))
+         => AddHeader h v a new where
     addHeader a resp = Headers resp (HCons (Header a) HNil)
 
 type family Contains x xs where
diff --git a/src/Servant/API/Sub.hs b/src/Servant/API/Sub.hs
--- a/src/Servant/API/Sub.hs
+++ b/src/Servant/API/Sub.hs
@@ -20,7 +20,6 @@
 
 -- $setup
 -- >>> import Servant.API
--- >>> import Servant.Common.Text
 -- >>> import Data.Aeson
 -- >>> import Data.Text
 -- >>> data World
diff --git a/src/Servant/API/Vault.hs b/src/Servant/API/Vault.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/API/Vault.hs
@@ -0,0 +1,20 @@
+module Servant.API.Vault
+  ( -- $vault
+    Vault
+  ) where
+
+import           Data.Vault.Lazy (Vault)
+
+-- $vault
+--
+-- | Use 'Vault' in your API types to provide access to the 'Vault'
+--   of the request, which is a location shared by middlewares and applications
+--   to store arbitrary data. See 'Vault' for more details on how to actually
+--   use the vault in your handlers
+--
+-- Example:
+--
+-- >>> type API = Vault :> Get '[JSON] String
+
+-- $setup
+-- >>> import Servant.API
diff --git a/src/Servant/API/Verbs.hs b/src/Servant/API/Verbs.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/API/Verbs.hs
@@ -0,0 +1,169 @@
+{-# LANGUAGE DataKinds          #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric      #-}
+{-# LANGUAGE KindSignatures     #-}
+{-# LANGUAGE PolyKinds          #-}
+module Servant.API.Verbs
+  ( module Servant.API.Verbs
+  , StdMethod(GET, POST, HEAD, PUT, DELETE, TRACE, CONNECT, OPTIONS, PATCH)
+  ) where
+
+import           Data.Typeable             (Typeable)
+import           Data.Proxy                (Proxy)
+import           GHC.Generics              (Generic)
+import           GHC.TypeLits              (Nat)
+import           Network.HTTP.Types.Method (Method, StdMethod (..),
+                                            methodDelete, methodGet, methodHead,
+                                            methodPatch, methodPost, methodPut)
+
+-- | @Verb@ is a general type for representing HTTP verbs (a.k.a. methods). For
+-- convenience, type synonyms for each verb with a 200 response code are
+-- provided, but you are free to define your own:
+--
+-- >>> type Post204 contentTypes a = Verb 'POST 204 contentTypes a
+data Verb (method :: k1) (statusCode :: Nat) (contentTypes :: [*]) a
+  deriving (Typeable, Generic)
+
+-- * 200 responses
+--
+-- The 200 response is the workhorse of web servers, but also fairly generic.
+-- When appropriate, you should prefer the more specific success combinators.
+-- More information about the definitions of status codes can be found in
+-- <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html RFC2615> and
+-- <https://tools.ietf.org/html/rfc7231#section-6 RFC7231 Section 6>;
+-- the relevant information is summarily presented here.
+
+-- | 'GET' with 200 status code.
+type Get    = Verb 'GET    200
+-- | 'POST' with 200 status code.
+type Post   = Verb 'POST   200
+-- | 'PUT' with 200 status code.
+type Put    = Verb 'PUT    200
+-- | 'DELETE' with 200 status code.
+type Delete = Verb 'DELETE 200
+-- | 'PATCH' with 200 status code.
+type Patch  = Verb 'PATCH  200
+
+-- * Other responses
+
+-- ** 201 Created
+--
+-- Indicates that a new resource has been created. The URI corresponding to the
+-- resource should be given in the @Location@ header field.
+--
+-- If the resource cannot be created immediately, use 'PostAccepted'.
+--
+-- Consider using 'Servant.Utils.Links.safeLink' for the @Location@ header
+-- field.
+
+-- | 'POST' with 201 status code.
+--
+type PostCreated = Verb 'POST 201
+
+
+-- ** 202 Accepted
+--
+-- Indicates that the request has been accepted for processing, but the
+-- processing has not yet completed. The status of the processing should be
+-- included, as well as either a link to a status monitoring endpoint or an
+-- estimate of when the processing will be finished.
+
+-- | 'GET' with 202 status code.
+type GetAccepted    = Verb 'GET 202
+-- | 'POST' with 202 status code.
+type PostAccepted   = Verb 'POST 202
+-- | 'DELETE' with 202 status code.
+type DeleteAccepted = Verb 'DELETE 202
+-- | 'PATCH' with 202 status code.
+type PatchAccepted  = Verb 'PATCH 202
+-- | 'PUT' with 202 status code.
+type PutAccepted    = Verb 'PUT 202
+
+
+-- ** 203 Non-Authoritative Information
+--
+-- Indicates that the request has been successfully processed, but the
+-- information may come from a third-party.
+
+-- | 'GET' with 203 status code.
+type GetNonAuthoritative    = Verb 'GET 203
+-- | 'POST' with 203 status code.
+type PostNonAuthoritative   = Verb 'POST 203
+-- | 'DELETE' with 203 status code.
+type DeleteNonAuthoritative = Verb 'DELETE 203
+-- | 'PATCH' with 203 status code.
+type PatchNonAuthoritative  = Verb 'PATCH 203
+-- | 'PUT' with 203 status code.
+type PutNonAuthoritative    = Verb 'PUT 203
+
+
+-- ** 204 No Content
+--
+-- Indicates that no response body is being returned. Handlers for these should
+-- return 'NoContent', possibly with headers.
+--
+-- If the document view should be reset, use @205 Reset Content@.
+
+-- | 'GET' with 204 status code.
+type GetNoContent    = Verb 'GET 204
+-- | 'POST' with 204 status code.
+type PostNoContent   = Verb 'POST 204
+-- | 'DELETE' with 204 status code.
+type DeleteNoContent = Verb 'DELETE 204
+-- | 'PATCH' with 204 status code.
+type PatchNoContent  = Verb 'PATCH 204
+-- | 'PUT' with 204 status code.
+type PutNoContent    = Verb 'PUT 204
+
+
+-- ** 205 Reset Content
+--
+-- Indicates that no response body is being returned. Handlers for these should
+-- return 'NoContent', possibly with Headers.
+--
+-- If the document view should not be reset, use @204 No Content@.
+
+-- | 'GET' with 205 status code.
+type GetResetContent    = Verb 'GET 205
+-- | 'POST' with 205 status code.
+type PostResetContent   = Verb 'POST 205
+-- | 'DELETE' with 205 status code.
+type DeleteResetContent = Verb 'DELETE 205
+-- | 'PATCH' with 205 status code.
+type PatchResetContent  = Verb 'PATCH 205
+-- | 'PUT' with 205 status code.
+type PutResetContent    = Verb 'PUT 205
+
+
+-- ** 206 Partial Content
+--
+-- Indicates that the server is delivering part of the resource due to a range
+-- header in the request.
+--
+-- For more information, see <https://tools.ietf.org/html/rfc7233#section-4.1
+-- RFC7233 Section 4.1>
+
+-- | 'GET' with 206 status code.
+type GetPartialContent = Verb 'GET 206
+
+
+class ReflectMethod a where
+    reflectMethod :: Proxy a -> Method
+
+instance ReflectMethod 'GET where
+    reflectMethod _ = methodGet
+
+instance ReflectMethod 'POST where
+    reflectMethod _ = methodPost
+
+instance ReflectMethod 'PUT where
+    reflectMethod _ = methodPut
+
+instance ReflectMethod 'DELETE where
+    reflectMethod _ = methodDelete
+
+instance ReflectMethod 'PATCH where
+    reflectMethod _ = methodPatch
+
+instance ReflectMethod 'HEAD where
+    reflectMethod _ = methodHead
diff --git a/src/Servant/API/WithNamedContext.hs b/src/Servant/API/WithNamedContext.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/API/WithNamedContext.hs
@@ -0,0 +1,21 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE KindSignatures #-}
+
+module Servant.API.WithNamedContext where
+
+import GHC.TypeLits
+
+-- | 'WithNamedContext' names a specific tagged context to use for the
+-- combinators in the API. (See also in @servant-server@,
+-- @Servant.Server.Context@.) For example:
+--
+-- > type UseNamedContextAPI = WithNamedContext "myContext" '[String] (
+-- >     ReqBody '[JSON] Int :> Get '[JSON] Int)
+--
+-- Both the 'ReqBody' and 'Get' combinators will use the 'WithNamedContext' with
+-- type tag "myContext" as their context.
+--
+-- 'Context's are only relevant for @servant-server@.
+--
+-- For more information, see the tutorial.
+data WithNamedContext (name :: Symbol) (subContext :: [*]) subApi
diff --git a/src/Servant/Common/Text.hs b/src/Servant/Common/Text.hs
deleted file mode 100644
--- a/src/Servant/Common/Text.hs
+++ /dev/null
@@ -1,149 +0,0 @@
-{-# LANGUAGE CPP                  #-}
-{-# LANGUAGE FlexibleInstances    #-}
-{-# LANGUAGE OverloadedStrings    #-}
-{-# LANGUAGE TypeSynonymInstances #-}
-module Servant.Common.Text
-  ( FromText(..)
-  , ToText(..)
-  ) where
-
-#if !MIN_VERSION_base(4,8,0)
-import           Control.Applicative     ((<$>))
-#endif
-import           Data.Int                (Int16, Int32, Int64, Int8)
-import           Data.String.Conversions (cs)
-import           Data.Text               (Text)
-import           Data.Text.Read          (Reader, decimal, rational, signed)
-import           Data.Word               (Word16, Word32, Word64, Word8
-#if !MIN_VERSION_base(4,8,0)
-        , Word
-#endif
-        )
-
--- | For getting values from url captures and query string parameters
--- Instances should obey:
--- > fromText (toText a) == Just a
-class FromText a where
-  fromText :: Text -> Maybe a
-
--- | For putting values in paths and query string parameters
--- Instances should obey:
--- > fromText (toText a) == Just a
-class ToText a where
-  toText :: a -> Text
-
-instance FromText Text where
-  fromText = Just
-
-instance ToText Text where
-  toText = id
-
-instance FromText String where
-  fromText = Just . cs
-
-instance ToText String where
-  toText = cs
-
--- |
--- >>> fromText ("true"::Text) :: Maybe Bool
--- Just True
--- >>> fromText ("false"::Text) :: Maybe Bool
--- Just False
--- >>> fromText ("anything else"::Text) :: Maybe Bool
--- Nothing
-instance FromText Bool where
-  fromText "true"  = Just True
-  fromText "false" = Just False
-  fromText _       = Nothing
-
--- |
--- >>> toText True
--- "true"
--- >>> toText False
--- "false"
-instance ToText Bool where
-  toText True  = "true"
-  toText False = "false"
-
-instance FromText Int where
-  fromText = runReader (signed decimal)
-
-instance ToText Int where
-  toText = cs . show
-
-instance FromText Int8 where
-  fromText = runReader (signed decimal)
-
-instance ToText Int8 where
-  toText = cs . show
-
-instance FromText Int16 where
-  fromText = runReader (signed decimal)
-
-instance ToText Int16 where
-  toText = cs . show
-
-instance FromText Int32 where
-  fromText = runReader (signed decimal)
-
-instance ToText Int32 where
-  toText = cs . show
-
-instance FromText Int64 where
-  fromText = runReader (signed decimal)
-
-instance ToText Int64 where
-  toText = cs . show
-
-instance FromText Word where
-  fromText = runReader decimal
-
-instance ToText Word where
-  toText = cs . show
-
-instance FromText Word8 where
-  fromText = runReader decimal
-
-instance ToText Word8 where
-  toText = cs . show
-
-instance FromText Word16 where
-  fromText = runReader decimal
-
-instance ToText Word16 where
-  toText = cs . show
-
-instance FromText Word32 where
-  fromText = runReader decimal
-
-instance ToText Word32 where
-  toText = cs . show
-
-instance FromText Word64 where
-  fromText = runReader decimal
-
-instance ToText Word64 where
-  toText = cs . show
-
-instance FromText Integer where
-  fromText = runReader (signed decimal)
-
-instance ToText Integer where
-  toText = cs . show
-
-instance FromText Double where
-  fromText x = fromRational <$> runReader rational x
-
-instance ToText Double where
-  toText = cs . show
-
-instance FromText Float where
-  -- Double is more practically accurate due to weird rounding when using
-  -- rational. We convert to double and then convert to Float.
-  fromText x = fromRational <$> runReader rational x
-
-instance ToText Float where
-  toText = cs . show
-
-runReader :: Reader a -> Text -> Maybe a
-runReader reader t = either (const Nothing) (Just . fst) $ reader t
diff --git a/src/Servant/Utils/Links.hs b/src/Servant/Utils/Links.hs
--- a/src/Servant/Utils/Links.hs
+++ b/src/Servant/Utils/Links.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE CPP                    #-}
 {-# LANGUAGE ConstraintKinds        #-}
 {-# LANGUAGE DataKinds              #-}
 {-# LANGUAGE FlexibleInstances      #-}
@@ -49,7 +48,7 @@
 -- or without those:
 --
 -- >>> let with = Proxy :: Proxy ("bye" :> QueryParam "name" String :> Delete '[JSON] ())
--- >>> print $ safeLink api with "Hubert"
+-- >>> print $ safeLink api with (Just "Hubert")
 -- bye?name=Hubert
 --
 -- >>> let without = Proxy :: Proxy ("bye" :> Delete '[JSON] ())
@@ -74,7 +73,7 @@
 -- >>> safeLink api bad_link
 -- ...
 --     Could not deduce (Or
---                         (IsElem' (Delete '[JSON] ()) (Get '[JSON] Int))
+--                         (IsElem' (Verb 'DELETE 200 '[JSON] ()) (Verb 'GET 200 '[JSON] Int))
 --                         (IsElem'
 --                            ("hello" :> Delete '[JSON] ())
 --                            ("bye" :> (QueryParam "name" String :> Delete '[JSON] ()))))
@@ -101,28 +100,23 @@
   , Or
 ) where
 
-import Data.List
-import Data.Proxy ( Proxy(..) )
-import Data.Text (Text, unpack)
-#if !MIN_VERSION_base(4,8,0)
-import Data.Monoid ( Monoid(..), (<>) )
-#else
-import Data.Monoid ( (<>) )
-#endif
-import Network.URI ( URI(..), escapeURIString, isUnreserved )
-import GHC.TypeLits ( KnownSymbol, symbolVal )
-import GHC.Exts(Constraint)
+import qualified Data.ByteString.Char8 as BSC
+import           Data.List
+import           Data.Monoid.Compat    ( (<>) )
+import           Data.Proxy            ( Proxy(..) )
+import qualified Data.Text             as Text
+import           GHC.Exts              (Constraint)
+import           GHC.TypeLits          ( KnownSymbol, symbolVal )
+import           Network.URI           ( URI(..), escapeURIString, isUnreserved )
+import           Prelude               ()
+import           Prelude.Compat
 
-import Servant.Common.Text
+import Web.HttpApiData
 import Servant.API.Capture ( Capture )
 import Servant.API.ReqBody ( ReqBody )
 import Servant.API.QueryParam ( QueryParam, QueryParams, QueryFlag )
-import Servant.API.MatrixParam ( MatrixParam, MatrixParams, MatrixFlag )
 import Servant.API.Header ( Header )
-import Servant.API.Get ( Get )
-import Servant.API.Post ( Post )
-import Servant.API.Put ( Put )
-import Servant.API.Delete ( Delete )
+import Servant.API.Verbs ( Verb )
 import Servant.API.Sub ( type (:>) )
 import Servant.API.Raw ( Raw )
 import Servant.API.Alternative ( type (:<|>) )
@@ -135,6 +129,10 @@
   , _queryParams :: [Param Query]
   } deriving Show
 
+instance ToHttpApiData Link where
+    toUrlPiece = Text.pack . show
+    toHeader   = BSC.pack . show
+
 -- | If either a or b produce an empty constraint, produce an empty constraint.
 type family Or (a :: Constraint) (b :: Constraint) :: Constraint where
     -- This works because of:
@@ -165,38 +163,33 @@
 type family IsElem endpoint api :: Constraint where
     IsElem e (sa :<|> sb)                   = Or (IsElem e sa) (IsElem e sb)
     IsElem (e :> sa) (e :> sb)              = IsElem sa sb
-    IsElem sa (Header x :> sb)              = IsElem sa sb
+    IsElem sa (Header sym x :> sb)          = IsElem sa sb
     IsElem sa (ReqBody y x :> sb)           = IsElem sa sb
     IsElem (Capture z y :> sa) (Capture x y :> sb)
                                             = IsElem sa sb
     IsElem sa (QueryParam x y :> sb)        = IsElem sa sb
     IsElem sa (QueryParams x y :> sb)       = IsElem sa sb
     IsElem sa (QueryFlag x :> sb)           = IsElem sa sb
-    IsElem sa (MatrixParam x y :> sb)       = IsElem sa sb
-    IsElem sa (MatrixParams x y :> sb)      = IsElem sa sb
-    IsElem sa (MatrixFlag x :> sb)          = IsElem sa sb
-    IsElem (Get ct typ) (Get ct' typ)       = IsSubList ct ct'
-    IsElem (Post ct typ) (Post ct' typ)     = IsSubList ct ct'
-    IsElem (Put ct typ) (Put ct' typ)       = IsSubList ct ct'
-    IsElem (Delete ct typ) (Delete ct' typ) = IsSubList ct ct'
+    IsElem (Verb m s ct typ) (Verb m s ct' typ)
+                                            = IsSubList ct ct'
     IsElem e e                              = ()
     IsElem e a                              = IsElem' e a
 
-
 type family IsSubList a b :: Constraint where
     IsSubList '[] b          = ()
-    IsSubList '[x] (x ': xs) = ()
-    IsSubList '[x] (y ': ys) = IsSubList '[x] ys
-    IsSubList (x ': xs) y    = IsSubList '[x] y `And` IsSubList xs y
+    IsSubList (x ': xs) y    = Elem x y `And` IsSubList xs y
 
+type family Elem e es :: Constraint where
+    Elem x (x ': xs) = ()
+    Elem y (x ': xs) = Elem y xs
+
 -- Phantom types for Param
-data Matrix
 data Query
 
--- | Query/Matrix param
+-- | Query param
 data Param a
-    = SingleParam    String Text
-    | ArrayElemParam String Text
+    = SingleParam    String Text.Text
+    | ArrayElemParam String Text.Text
     | FlagParam      String
   deriving Show
 
@@ -207,21 +200,6 @@
 addQueryParam qp l =
     l { _queryParams = _queryParams l <> [qp] }
 
--- Not particularly efficient for many updates. Something to optimise if it's
--- a problem.
-addMatrixParam :: Param Matrix -> Link -> Link
-addMatrixParam param l = l { _segments = f (_segments l) }
-  where
-    f [] = []
-    f xs = init xs <> [g (last xs)]
-    -- Modify the segment at the "top" of the stack
-    g :: String -> String
-    g seg =
-        case param of
-            SingleParam k v    -> seg <> ";" <> k <> "=" <> escape (unpack v)
-            ArrayElemParam k v -> seg <> ";" <> k <> "[]=" <> escape (unpack v)
-            FlagParam k        -> seg <> ";" <> k
-
 linkURI :: Link -> URI
 linkURI (Link segments q_params) =
     URI mempty  -- No scheme (relative)
@@ -235,8 +213,8 @@
         "?" <> intercalate "&" (fmap makeQuery xs)
 
     makeQuery :: Param Query -> String
-    makeQuery (ArrayElemParam k v) = escape k <> "[]=" <> escape (unpack v)
-    makeQuery (SingleParam k v)    = escape k <> "=" <> escape (unpack v)
+    makeQuery (ArrayElemParam k v) = escape k <> "[]=" <> escape (Text.unpack v)
+    makeQuery (SingleParam k v)    = escape k <> "=" <> escape (Text.unpack v)
     makeQuery (FlagParam k)        = escape k
 
 escape :: String -> String
@@ -269,22 +247,22 @@
 
 
 -- QueryParam instances
-instance (KnownSymbol sym, ToText v, HasLink sub)
+instance (KnownSymbol sym, ToHttpApiData v, HasLink sub)
     => HasLink (QueryParam sym v :> sub) where
-    type MkLink (QueryParam sym v :> sub) = v -> MkLink sub
-    toLink _ l v =
-        toLink (Proxy :: Proxy sub)
-             (addQueryParam (SingleParam k (toText v)) l)
+    type MkLink (QueryParam sym v :> sub) = Maybe v -> MkLink sub
+    toLink _ l mv =
+        toLink (Proxy :: Proxy sub) $
+            maybe id (addQueryParam . SingleParam k . toQueryParam) mv l
       where
         k :: String
         k = symbolVal (Proxy :: Proxy sym)
 
-instance (KnownSymbol sym, ToText v, HasLink sub)
+instance (KnownSymbol sym, ToHttpApiData v, HasLink sub)
     => HasLink (QueryParams sym v :> sub) where
     type MkLink (QueryParams sym v :> sub) = [v] -> MkLink sub
     toLink _ l =
         toLink (Proxy :: Proxy sub) .
-            foldl' (\l' v -> addQueryParam (ArrayElemParam k (toText v)) l') l
+            foldl' (\l' v -> addQueryParam (ArrayElemParam k (toQueryParam v)) l') l
       where
         k = symbolVal (Proxy :: Proxy sym)
 
@@ -298,66 +276,25 @@
       where
         k = symbolVal (Proxy :: Proxy sym)
 
--- MatrixParam instances
-instance (KnownSymbol sym, ToText v, HasLink sub)
-    => HasLink (MatrixParam sym v :> sub) where
-    type MkLink (MatrixParam sym v :> sub) = v -> MkLink sub
-    toLink _ l v =
-        toLink (Proxy :: Proxy sub) $
-            addMatrixParam (SingleParam k (toText v)) l
-      where
-        k = symbolVal (Proxy :: Proxy sym)
-
-instance (KnownSymbol sym, ToText v, HasLink sub)
-    => HasLink (MatrixParams sym v :> sub) where
-    type MkLink (MatrixParams sym v :> sub) = [v] -> MkLink sub
-    toLink _ l =
-        toLink (Proxy :: Proxy sub) .
-            foldl' (\l' v -> addMatrixParam (ArrayElemParam k (toText v)) l') l
-      where
-        k = symbolVal (Proxy :: Proxy sym)
-
-instance (KnownSymbol sym, HasLink sub)
-    => HasLink (MatrixFlag sym :> sub) where
-    type MkLink (MatrixFlag sym :> sub) = Bool -> MkLink sub
-    toLink _ l False =
-        toLink (Proxy :: Proxy sub) l
-    toLink _ l True =
-        toLink (Proxy :: Proxy sub) $ addMatrixParam (FlagParam k) l
-      where
-        k = symbolVal (Proxy :: Proxy sym)
-
 -- Misc instances
 instance HasLink sub => HasLink (ReqBody ct a :> sub) where
     type MkLink (ReqBody ct a :> sub) = MkLink sub
     toLink _ = toLink (Proxy :: Proxy sub)
 
-instance (ToText v, HasLink sub)
+instance (ToHttpApiData v, HasLink sub)
     => HasLink (Capture sym v :> sub) where
     type MkLink (Capture sym v :> sub) = v -> MkLink sub
     toLink _ l v =
         toLink (Proxy :: Proxy sub) $
-            addSegment (escape . unpack $ toText v) l
+            addSegment (escape . Text.unpack $ toUrlPiece v) l
 
 instance HasLink sub => HasLink (Header sym a :> sub) where
     type MkLink (Header sym a :> sub) = MkLink sub
     toLink _ = toLink (Proxy :: Proxy sub)
 
 -- Verb (terminal) instances
-instance HasLink (Get y r) where
-    type MkLink (Get y r) = URI
-    toLink _ = linkURI
-
-instance HasLink (Post y r) where
-    type MkLink (Post y r) = URI
-    toLink _ = linkURI
-
-instance HasLink (Put y r) where
-    type MkLink (Put y r) = URI
-    toLink _ = linkURI
-
-instance HasLink (Delete y r) where
-    type MkLink (Delete y r) = URI
+instance HasLink (Verb m s ct a) where
+    type MkLink (Verb m s ct a) = URI
     toLink _ = linkURI
 
 instance HasLink Raw where
diff --git a/test/Doctests.hs b/test/Doctests.hs
--- a/test/Doctests.hs
+++ b/test/Doctests.hs
@@ -1,6 +1,6 @@
 module Main where
 
-import           Data.List (isPrefixOf)
+import           Data.List            (isPrefixOf)
 import           System.Directory
 import           System.FilePath
 import           System.FilePath.Find
@@ -9,21 +9,32 @@
 main :: IO ()
 main = do
     files <- find always (extension ==? ".hs") "src"
-    cabalMacrosFile <- getCabalMacrosFile
-    doctest $ [ "-isrc"
-              , "-optP-include"
-              , "-optP" ++ cabalMacrosFile
-              , "-XOverloadedStrings"
-              , "-XFlexibleInstances"
-              , "-XMultiParamTypeClasses"
-              ] ++ files
+    tfiles <- find always (extension ==? ".hs") "test/Servant"
+    mCabalMacrosFile <- getCabalMacrosFile
+    doctest $ "-isrc" : "-Iinclude" :
+              (maybe [] (\ f -> ["-optP-include", "-optP" ++ f]) mCabalMacrosFile) ++
+              "-XOverloadedStrings" :
+              "-XFlexibleInstances" :
+              "-XMultiParamTypeClasses" :
+              (files ++ tfiles)
 
-getCabalMacrosFile :: IO FilePath
+getCabalMacrosFile :: IO (Maybe FilePath)
 getCabalMacrosFile = do
-  contents <- getDirectoryContents "dist"
-  let rest = "build" </> "autogen" </> "cabal_macros.h"
-  return $ case filter ("dist-sandbox-" `isPrefixOf`) contents of
-    [x] -> "dist" </> x </> rest
-    [] -> "dist" </> rest
-    xs -> error $ "ran doctests with multiple dist/dist-sandbox-xxxxx's: \n"
-                ++ show xs ++ "\nTry cabal clean"
+  exists <- doesDirectoryExist "dist"
+  if exists
+    then do
+      contents <- getDirectoryContents "dist"
+      let rest = "build" </> "autogen" </> "cabal_macros.h"
+      whenExists $ case filter ("dist-sandbox-" `isPrefixOf`) contents of
+        [x] -> "dist" </> x </> rest
+        [] -> "dist" </> rest
+        xs -> error $ "ran doctests with multiple dist/dist-sandbox-xxxxx's: \n"
+                    ++ show xs ++ "\nTry cabal clean"
+    else return Nothing
+ where
+  whenExists :: FilePath -> IO (Maybe FilePath)
+  whenExists file = do
+    exists <- doesFileExist file
+    return $ if exists
+      then Just file
+      else Nothing
diff --git a/test/Servant/API/ContentTypesSpec.hs b/test/Servant/API/ContentTypesSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Servant/API/ContentTypesSpec.hs
@@ -0,0 +1,225 @@
+{-# LANGUAGE CPP                   #-}
+{-# LANGUAGE DataKinds             #-}
+{-# LANGUAGE DeriveGeneric         #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE PolyKinds             #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Servant.API.ContentTypesSpec where
+
+#if !MIN_VERSION_base(4,8,0)
+import           Control.Applicative
+import           Data.Monoid
+#endif
+import           Control.Arrow
+import           Data.Aeson
+import           Data.ByteString.Char8     (ByteString, append, pack)
+import qualified Data.ByteString.Lazy      as BSL
+import           Data.Either
+import           Data.Function             (on)
+import           Data.List                 (maximumBy)
+import           Data.Maybe                (fromJust, isJust, isNothing)
+import           Data.Proxy
+import           Data.String               (IsString (..))
+import           Data.String.Conversions   (cs)
+import qualified Data.Text                 as TextS
+import qualified Data.Text.Lazy            as TextL
+import           GHC.Generics
+import           Network.URL               (exportParams, importParams)
+import           Test.Hspec
+import           Test.QuickCheck
+import           Test.QuickCheck.Instances ()
+
+import           Servant.API.ContentTypes
+
+spec :: Spec
+spec = describe "Servant.API.ContentTypes" $ do
+
+    describe "handleAcceptH" $ do
+        let p = Proxy :: Proxy '[PlainText]
+
+        it "matches any charset if none were provided" $ do
+            let without = handleAcceptH p (AcceptHeader "text/plain")
+                with    = handleAcceptH p (AcceptHeader "text/plain;charset=utf-8")
+                wisdom  = "ubi sub ubi" :: String
+            without wisdom `shouldBe` with wisdom
+
+        it "does not match non utf-8 charsets" $  do
+            let badCharset = handleAcceptH p (AcceptHeader "text/plain;charset=whoknows")
+                s          = "cheese" :: String
+            badCharset s `shouldBe` Nothing
+
+    describe "The JSON Content-Type type" $ do
+        let p = Proxy :: Proxy JSON
+
+        it "handles whitespace at end of input" $ do
+            mimeUnrender p "[1] " `shouldBe` Right [1 :: Int]
+
+        it "handles whitespace at beginning of input" $ do
+            mimeUnrender p " [1] " `shouldBe` Right [1 :: Int]
+
+        it "does not like junk at end of input" $ do
+            mimeUnrender p "[1] this probably shouldn't work"
+              `shouldSatisfy` (isLeft :: Either a [Int] -> Bool)
+
+        it "has mimeUnrender reverse mimeRender for valid top-level json ([Int]) " $ do
+            property $ \x -> mimeUnrender p (mimeRender p x) == Right (x::[Int])
+
+        it "has mimeUnrender reverse mimeRender for valid top-level json " $ do
+            property $ \x -> mimeUnrender p (mimeRender p x) == Right (x::SomeData)
+
+    describe "The FormUrlEncoded Content-Type type" $ do
+        let p = Proxy :: Proxy FormUrlEncoded
+
+        it "has mimeUnrender reverse mimeRender" $ do
+            property $ \x -> mempty `notElem` x
+                ==> mimeUnrender p (mimeRender p x) == Right (x::[(TextS.Text,TextS.Text)])
+
+        it "has mimeUnrender reverse exportParams (Network.URL)" $ do
+            property $ \x -> mempty `notElem` x
+                ==> (mimeUnrender p . cs . exportParams . map (cs *** cs) $ x) == Right (x::[(TextS.Text,TextS.Text)])
+
+        it "has importParams (Network.URL) reverse mimeRender" $ do
+            property $ \x -> mempty `notElem` x
+                ==> (fmap (map (cs *** cs)) . importParams . cs . mimeRender p $ x) == Just (x::[(TextS.Text,TextS.Text)])
+
+    describe "The PlainText Content-Type type" $ do
+        let p = Proxy :: Proxy PlainText
+
+        it "has mimeUnrender reverse mimeRender (lazy Text)" $ do
+            property $ \x -> mimeUnrender p (mimeRender p x) == Right (x::TextL.Text)
+
+        it "has mimeUnrender reverse mimeRender (strict Text)" $ do
+            property $ \x -> mimeUnrender p (mimeRender p x) == Right (x::TextS.Text)
+
+    describe "The OctetStream Content-Type type" $ do
+        let p = Proxy :: Proxy OctetStream
+
+        it "is id (Lazy ByteString)" $ do
+            property $ \x -> mimeRender p x == (x :: BSL.ByteString)
+                && mimeUnrender p x == Right x
+
+        it "is fromStrict/toStrict (Strict ByteString)" $ do
+            property $ \x -> mimeRender p x == BSL.fromStrict (x :: ByteString)
+                && mimeUnrender p (BSL.fromStrict x) == Right x
+
+    describe "handleAcceptH" $ do
+
+        it "returns Nothing if the 'Accept' header doesn't match" $ do
+            handleAcceptH (Proxy :: Proxy '[JSON]) "text/plain" (3 :: Int)
+                `shouldSatisfy` isNothing
+
+        it "returns Just if the 'Accept' header matches" $ do
+            handleAcceptH (Proxy :: Proxy '[JSON]) "*/*" (3 :: Int)
+                `shouldSatisfy` isJust
+            handleAcceptH (Proxy :: Proxy '[PlainText, JSON]) "application/json" (3 :: Int)
+                `shouldSatisfy` isJust
+            handleAcceptH (Proxy :: Proxy '[PlainText, JSON, OctetStream])
+                "application/octet-stream" ("content" :: ByteString)
+                `shouldSatisfy` isJust
+
+        it "returns the Content-Type as the first element of the tuple" $ do
+            handleAcceptH (Proxy :: Proxy '[JSON]) "*/*" (3 :: Int)
+                `shouldSatisfy` ((== "application/json") . fst . fromJust)
+            handleAcceptH (Proxy :: Proxy '[PlainText, JSON]) "application/json" (3 :: Int)
+                `shouldSatisfy` ((== "application/json") . fst . fromJust)
+            handleAcceptH (Proxy :: Proxy '[PlainText, JSON, OctetStream])
+                "application/octet-stream" ("content" :: ByteString)
+                `shouldSatisfy` ((== "application/octet-stream") . fst . fromJust)
+
+        it "returns the appropriately serialized representation" $ do
+            property $ \x -> handleAcceptH (Proxy :: Proxy '[JSON]) "*/*" (x :: SomeData)
+                == Just ("application/json", encode x)
+
+        it "respects the Accept spec ordering" $ do
+            let highest a b c = maximumBy (compare `on` snd)
+                        [ ("application/octet-stream", a)
+                        , ("application/json", b)
+                        , ("text/plain;charset=utf-8", c)
+                        ]
+            let acceptH a b c = addToAccept (Proxy :: Proxy OctetStream) a $
+                                    addToAccept (Proxy :: Proxy JSON) b $
+                                    addToAccept (Proxy :: Proxy PlainText ) c ""
+            let val a b c i = handleAcceptH (Proxy :: Proxy '[OctetStream, JSON, PlainText])
+                                            (acceptH a b c) (i :: Int)
+            property $ \a b c i -> fst (fromJust $ val a b c i) == fst (highest a b c)
+
+    describe "handleCTypeH" $ do
+
+        it "returns Nothing if the 'Content-Type' header doesn't match" $ do
+            handleCTypeH (Proxy :: Proxy '[JSON]) "text/plain" "𝓽𝓱𝓮 𝓽𝓲𝓶𝓮 𝓱𝓪𝓼 𝓬𝓸𝓶𝓮, 𝓽𝓱𝓮 𝔀𝓪𝓵𝓻𝓾𝓼 𝓼𝓪𝓲𝓭 "
+                `shouldBe` (Nothing :: Maybe (Either String Value))
+
+        context "the 'Content-Type' header matches" $ do
+            it "returns Just if the parameter matches" $ do
+                handleCTypeH (Proxy :: Proxy '[JSON]) "application/json"
+                    "𝕥𝕠 𝕥𝕒𝕝𝕜 𝕠𝕗 𝕞𝕒𝕟𝕪 𝕥𝕙𝕚𝕟𝕘𝕤 "
+                    `shouldSatisfy` (isJust :: Maybe (Either String Value) -> Bool)
+
+            it "returns Just if there is no parameter" $ do
+                handleCTypeH (Proxy :: Proxy '[JSON]) "application/json"
+                    "𝕥𝕠 𝕥𝕒𝕝𝕜 𝕠𝕗 𝕞𝕒𝕟𝕪 𝕥𝕙𝕚𝕟𝕘𝕤 "
+                    `shouldSatisfy` (isJust :: Maybe (Either String Value) -> Bool)
+
+            it "returns Just Left if the decoding fails" $ do
+                let isJustLeft :: Maybe (Either String Value) -> Bool
+                    isJustLeft (Just (Left _)) = True
+                    isJustLeft _ = False
+                handleCTypeH (Proxy :: Proxy '[JSON]) "application/json"
+                    "𝕺𝖋 𝖘𝖍𝖔𝖊𝖘--𝖆𝖓𝖉 𝖘𝖍𝖎𝖕𝖘--𝖆𝖓𝖉 𝖘𝖊𝖆𝖑𝖎𝖓𝖌-𝖜𝖆𝖝-- "
+                    `shouldSatisfy` isJustLeft
+
+            it "returns Just (Right val) if the decoding succeeds" $ do
+                let val = SomeData "Of cabbages--and kings" 12
+                handleCTypeH (Proxy :: Proxy '[JSON]) "application/json"
+                    (encode val)
+                    `shouldBe` Just (Right val)
+
+#if MIN_VERSION_aeson(0,9,0)
+    -- aeson >= 0.9 decodes top-level strings
+    describe "eitherDecodeLenient" $ do
+
+        it "parses top-level strings" $ do
+            let toMaybe = either (const Nothing) Just
+            -- The Left messages differ, so convert to Maybe
+            property $ \x -> toMaybe (eitherDecodeLenient x)
+                `shouldBe` (decode x :: Maybe String)
+#endif
+
+
+data SomeData = SomeData { record1 :: String, record2 :: Int }
+    deriving (Generic, Eq, Show)
+
+newtype ZeroToOne = ZeroToOne Float
+    deriving (Eq, Show, Ord)
+
+instance FromJSON SomeData
+
+instance ToJSON SomeData
+
+instance Arbitrary SomeData where
+    arbitrary = SomeData <$> arbitrary <*> arbitrary
+
+instance Arbitrary ZeroToOne where
+    arbitrary = ZeroToOne <$> elements [ x / 10 | x <- [1..10]]
+
+instance MimeRender OctetStream Int where
+    mimeRender _ = cs . show
+
+instance MimeRender PlainText Int where
+    mimeRender _ = cs . show
+
+instance MimeRender PlainText ByteString where
+    mimeRender _ = cs
+
+instance ToJSON ByteString where
+    toJSON x = object [ "val" .= x ]
+
+instance IsString AcceptHeader where
+    fromString = AcceptHeader . fromString
+
+addToAccept :: Accept a => Proxy a -> ZeroToOne -> AcceptHeader -> AcceptHeader
+addToAccept p (ZeroToOne f) (AcceptHeader h) = AcceptHeader (cont h)
+    where new = cs (show $ contentType p) `append` "; q=" `append` pack (show f)
+          cont "" = new
+          cont old = old `append` ", " `append` new
diff --git a/test/Servant/API/ResponseHeadersSpec.hs b/test/Servant/API/ResponseHeadersSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Servant/API/ResponseHeadersSpec.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE OverloadedStrings #-}
+module Servant.API.ResponseHeadersSpec where
+
+import Test.Hspec
+
+import Servant.API.Header
+import Servant.API.ResponseHeaders
+
+spec :: Spec
+spec = describe "Servant.API.ResponseHeaders" $ do
+  describe "addHeader" $ do
+
+    it "adds a header to a value" $ do
+      let val = addHeader "hi" 5 :: Headers '[Header "test" String] Int
+      getHeaders val `shouldBe` [("test", "hi")]
+
+    it "maintains the value" $ do
+      let val = addHeader "hi" 5 :: Headers '[Header "test" String] Int
+      getResponse val `shouldBe` 5
+
+    it "adds headers to the front of the list" $ do
+      let val = addHeader 10 $ addHeader "b" 5 :: Headers '[Header "first" Int, Header "second" String] Int
+      getHeaders val `shouldBe` [("first", "10"), ("second", "b")]
diff --git a/test/Servant/Utils/LinksSpec.hs b/test/Servant/Utils/LinksSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Servant/Utils/LinksSpec.hs
@@ -0,0 +1,101 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds       #-}
+{-# LANGUAGE PolyKinds       #-}
+{-# LANGUAGE TypeOperators   #-}
+module Servant.Utils.LinksSpec where
+
+import           Data.Proxy              (Proxy (..))
+import           Test.Hspec              (Expectation, Spec, describe, it,
+                                          shouldBe)
+
+import           Servant.API
+
+type TestApi =
+  -- Capture and query params
+       "hello" :> Capture "name" String :> QueryParam "capital" Bool :> Delete '[JSON] ()
+
+  -- Flags
+  :<|> "balls" :> QueryFlag "bouncy" :> QueryFlag "fast" :> Delete '[JSON] ()
+
+  -- All of the verbs
+  :<|> "get" :> Get '[JSON] ()
+  :<|> "put" :> Put '[JSON] ()
+  :<|> "post" :> ReqBody '[JSON] 'True :> Post '[JSON] ()
+  :<|> "delete" :> Header "ponies" String :> Delete '[JSON] ()
+  :<|> "raw" :> Raw
+
+
+apiLink :: (IsElem endpoint TestApi, HasLink endpoint)
+         => Proxy endpoint -> MkLink endpoint
+apiLink = safeLink (Proxy :: Proxy TestApi)
+
+-- | Convert a link to a URI and ensure that this maps to the given string
+-- given string
+shouldBeURI :: URI -> String -> Expectation
+shouldBeURI link expected =
+    show link `shouldBe` expected
+
+spec :: Spec
+spec = describe "Servant.Utils.Links" $ do
+    it "generates correct links for capture query params" $ do
+        let l1 = Proxy :: Proxy ("hello" :> Capture "name" String :> Delete '[JSON] ())
+        apiLink l1 "hi" `shouldBeURI` "hello/hi"
+
+        let l2 = Proxy :: Proxy ("hello" :> Capture "name" String
+                                         :> QueryParam "capital" Bool
+                                         :> Delete '[JSON] ())
+        apiLink l2 "bye" (Just True) `shouldBeURI` "hello/bye?capital=true"
+
+
+    it "generates correct links for query flags" $ do
+        let l1 = Proxy :: Proxy ("balls" :> QueryFlag "bouncy"
+                                         :> QueryFlag "fast" :> Delete '[JSON] ())
+        apiLink l1 True True `shouldBeURI` "balls?bouncy&fast"
+        apiLink l1 False True `shouldBeURI` "balls?fast"
+
+    it "generates correct links for all of the verbs" $ do
+        apiLink (Proxy :: Proxy ("get" :> Get '[JSON] ())) `shouldBeURI` "get"
+        apiLink (Proxy :: Proxy ("put" :> Put '[JSON] ())) `shouldBeURI` "put"
+        apiLink (Proxy :: Proxy ("post" :> Post '[JSON] ())) `shouldBeURI` "post"
+        apiLink (Proxy :: Proxy ("delete" :> Delete '[JSON] ())) `shouldBeURI` "delete"
+        apiLink (Proxy :: Proxy ("raw" :> Raw)) `shouldBeURI` "raw"
+
+
+-- |
+-- Before https://github.com/CRogers/should-not-typecheck/issues/5 is fixed,
+-- we'll just use doctest
+--
+-- >>> apiLink (Proxy :: Proxy WrongPath)
+-- ...
+--     Could not deduce ...
+-- ...
+--
+-- >>> apiLink (Proxy :: Proxy WrongReturnType)
+-- ...
+--     Could not deduce ...
+-- ...
+--
+-- >>> apiLink (Proxy :: Proxy WrongContentType)
+-- ...
+--     Could not deduce ...
+-- ...
+--
+-- >>> apiLink (Proxy :: Proxy WrongMethod)
+-- ...
+--     Could not deduce ...
+-- ...
+--
+-- >>> apiLink (Proxy :: Proxy NotALink)
+-- ...
+--     Could not deduce ...
+-- ...
+--
+-- sanity check
+-- >>> apiLink (Proxy :: Proxy AllGood)
+-- get
+type WrongPath = "getTypo" :> Get '[JSON] ()
+type WrongReturnType = "get" :> Get '[JSON] Bool
+type WrongContentType = "get" :> Get '[OctetStream] ()
+type WrongMethod = "get" :> Post '[JSON] ()
+type NotALink = "hello" :> ReqBody '[JSON] 'True :> Get '[JSON] Bool
+type AllGood = "get" :> Get '[JSON] ()
