diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # ChangeLog for yesod-core
 
+## 1.6.17
+
+Adds `contentTypeIsJson` [#1646](https://github.com/yesodweb/yesod/pull/1646)
+
 ## 1.6.16.1
 
 * Compiles with GHC 8.8.1
diff --git a/src/Yesod/Core/Handler.hs b/src/Yesod/Core/Handler.hs
--- a/src/Yesod/Core/Handler.hs
+++ b/src/Yesod/Core/Handler.hs
@@ -91,7 +91,8 @@
     , permissionDeniedI
     , invalidArgs
     , invalidArgsI
-      -- ** Short-circuit responses.
+      -- ** Short-circuit responses
+      -- $rollbackWarning
     , sendFile
     , sendFilePart
     , sendResponse
@@ -606,6 +607,20 @@
 -- discards the rest and the status
 getMessage :: MonadHandler m => m (Maybe Html)
 getMessage = fmap (fmap snd . listToMaybe) getMessages
+
+-- $rollbackWarning
+--
+-- Note that since short-circuiting is implemented by using exceptions,
+-- using e.g. 'sendStatusJSON' inside a runDB block
+-- will result in the database actions getting rolled back:
+--
+-- @
+-- runDB $ do
+--   userId <- insert $ User "username" "email@example.com"
+--   postId <- insert $ BlogPost "title" "hi there!"
+--     /The previous two inserts will be rolled back./
+--   sendStatusJSON Status.status200 ()
+-- @
 
 -- | Bypass remaining handler code and output the given file.
 --
diff --git a/src/Yesod/Core/Json.hs b/src/Yesod/Core/Json.hs
--- a/src/Yesod/Core/Json.hs
+++ b/src/Yesod/Core/Json.hs
@@ -32,6 +32,9 @@
     , jsonOrRedirect
     , jsonEncodingOrRedirect
     , acceptsJson
+
+      -- * Checking if data is JSON
+    , contentTypeHeaderIsJson
     ) where
 
 import Yesod.Core.Handler (HandlerFor, getRequest, invalidArgs, redirect, selectRep, provideRep, rawRequestBody, ProvidedRep, lookupHeader)
@@ -134,8 +137,8 @@
 parseCheckJsonBody :: (MonadHandler m, J.FromJSON a) => m (J.Result a)
 parseCheckJsonBody = do
     mct <- lookupHeader "content-type"
-    case fmap (B8.takeWhile (/= ';')) mct of
-        Just "application/json" -> parseInsecureJsonBody
+    case fmap contentTypeHeaderIsJson mct of
+        Just True -> parseInsecureJsonBody
         _ -> return $ J.Error $ "Non-JSON content type: " ++ show mct
 
 -- | Same as 'parseInsecureJsonBody', but return an invalid args response on a parse
@@ -218,3 +221,12 @@
             .  listToMaybe
             .  reqAccept)
            `liftM` getRequest
+
+-- | Given the @Content-Type@ header, returns if it is JSON.
+--
+-- This function is currently a simple check for @application/json@, but in the future may check for
+-- alternative representations such as @<https://tools.ietf.org/html/rfc6839#section-3.1 xxx/yyy+json>@.
+--
+-- @since 1.6.17
+contentTypeHeaderIsJson :: B8.ByteString -> Bool
+contentTypeHeaderIsJson bs = B8.takeWhile (/= ';') bs == "application/json"
diff --git a/yesod-core.cabal b/yesod-core.cabal
--- a/yesod-core.cabal
+++ b/yesod-core.cabal
@@ -1,5 +1,5 @@
 name:            yesod-core
-version:         1.6.16.1
+version:         1.6.17
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -48,7 +48,6 @@
                    , primitive             >= 0.6
                    , random                >= 1.0.0.2  && < 1.2
                    , resourcet             >= 1.2
-                   , rio
                    , shakespeare           >= 2.0
                    , template-haskell      >= 2.11
                    , text                  >= 0.7
