Pass contentType to the mimeUnrender variant

This commit is contained in:
Oleg Grenrus 2016-10-12 07:28:43 +03:00
parent e8ba67048a
commit 4d4bc8e9f4
4 changed files with 31 additions and 6 deletions

View file

@ -111,10 +111,10 @@ test-suite spec
base == 4.* base == 4.*
, base-compat , base-compat
, aeson , aeson
, aeson-compat >=0.3.3 && <0.4
, attoparsec , attoparsec
, bytestring , bytestring
, hspec == 2.* , hspec == 2.*
, http-media
, QuickCheck , QuickCheck
, quickcheck-instances , quickcheck-instances
, servant , servant

View file

@ -206,6 +206,16 @@ instance OVERLAPPABLE_
-- --
class Accept ctype => MimeUnrender ctype a where class Accept ctype => MimeUnrender ctype a where
mimeUnrender :: Proxy ctype -> ByteString -> Either String a mimeUnrender :: Proxy ctype -> ByteString -> Either String a
mimeUnrender p = mimeUnrenderWithType p (contentType p)
-- | Variant which is given the actual 'M.MediaType' provided by the other party.
--
-- In the most cases you don't want to branch based on the 'M.MediaType'.
-- See <https://github.com/haskell-servant/servant/pull/552 pr552> for a motivating example.
mimeUnrenderWithType :: Proxy ctype -> M.MediaType -> ByteString -> Either String a
mimeUnrenderWithType p _ = mimeUnrender p
{-# MINIMAL mimeUnrender | mimeUnrenderWithType #-}
class AllCTUnrender (list :: [*]) a where class AllCTUnrender (list :: [*]) a where
handleCTypeH :: Proxy list handleCTypeH :: Proxy list
@ -290,10 +300,10 @@ instance ( MimeUnrender ctyp a
, AllMimeUnrender ctyps a , AllMimeUnrender ctyps a
) => AllMimeUnrender (ctyp ': ctyps) a where ) => AllMimeUnrender (ctyp ': ctyps) a where
allMimeUnrender _ bs = allMimeUnrender _ bs =
(map (, x) $ NE.toList $ contentTypes pctyp) (map mk $ NE.toList $ contentTypes pctyp)
++ allMimeUnrender pctyps bs ++ allMimeUnrender pctyps bs
where where
x = mimeUnrender pctyp bs mk ct = (ct, mimeUnrenderWithType pctyp ct bs)
pctyp = Proxy :: Proxy ctyp pctyp = Proxy :: Proxy ctyp
pctyps = Proxy :: Proxy ctyps pctyps = Proxy :: Proxy ctyps

View file

@ -11,7 +11,7 @@ module Servant.API.ContentTypesSpec where
import Prelude () import Prelude ()
import Prelude.Compat import Prelude.Compat
import Data.Aeson import Data.Aeson.Compat
import Data.ByteString.Char8 (ByteString, append, pack) import Data.ByteString.Char8 (ByteString, append, pack)
import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString.Lazy.Char8 as BSL8 import qualified Data.ByteString.Lazy.Char8 as BSL8
@ -24,9 +24,9 @@ import Data.Proxy
import Data.String (IsString (..)) import Data.String (IsString (..))
import Data.String.Conversions (cs) import Data.String.Conversions (cs)
import qualified Data.Text as TextS import qualified Data.Text as TextS
import qualified Data.Text.Encoding as TextSE
import qualified Data.Text.Lazy as TextL import qualified Data.Text.Lazy as TextL
import GHC.Generics import GHC.Generics
import qualified Network.HTTP.Media as M
import Test.Hspec import Test.Hspec
import Test.QuickCheck import Test.QuickCheck
import Text.Read (readMaybe) import Text.Read (readMaybe)
@ -179,6 +179,15 @@ spec = describe "Servant.API.ContentTypes" $ do
handleCTypeH (Proxy :: Proxy '[JSONorText]) "image/jpeg" handleCTypeH (Proxy :: Proxy '[JSONorText]) "image/jpeg"
"42" `shouldBe` (Nothing :: Maybe (Either String Int)) "42" `shouldBe` (Nothing :: Maybe (Either String Int))
it "passes content-type to mimeUnrenderWithType" $ do
let val = "foobar" :: TextS.Text
handleCTypeH (Proxy :: Proxy '[JSONorText]) "application/json"
"\"foobar\"" `shouldBe` Just (Right val)
handleCTypeH (Proxy :: Proxy '[JSONorText]) "text/plain"
"foobar" `shouldBe` Just (Right val)
handleCTypeH (Proxy :: Proxy '[JSONorText]) "image/jpeg"
"foobar" `shouldBe` (Nothing :: Maybe (Either String Int))
#if MIN_VERSION_aeson(0,9,0) #if MIN_VERSION_aeson(0,9,0)
-- aeson >= 0.9 decodes top-level strings -- aeson >= 0.9 decodes top-level strings
describe "eitherDecodeLenient" $ do describe "eitherDecodeLenient" $ do
@ -226,7 +235,7 @@ instance IsString AcceptHeader where
data JSONorText data JSONorText
instance Accept JSONorText where instance Accept JSONorText where
contentTypes _ = "text" M.// "plain" NE.:| [ "application" M.// "json" ] contentTypes _ = "text/plain" NE.:| [ "application/json" ]
instance MimeRender JSONorText Int where instance MimeRender JSONorText Int where
mimeRender _ = cs . show mimeRender _ = cs . show
@ -234,6 +243,11 @@ instance MimeRender JSONorText Int where
instance MimeUnrender JSONorText Int where instance MimeUnrender JSONorText Int where
mimeUnrender _ = maybe (Left "") Right . readMaybe . BSL8.unpack mimeUnrender _ = maybe (Left "") Right . readMaybe . BSL8.unpack
instance MimeUnrender JSONorText TextS.Text where
mimeUnrenderWithType _ mt
| mt == "application/json" = maybe (Left "") Right . decode
| otherwise = Right . TextSE.decodeUtf8 . BSL.toStrict
addToAccept :: Accept a => Proxy a -> ZeroToOne -> AcceptHeader -> AcceptHeader addToAccept :: Accept a => Proxy a -> ZeroToOne -> AcceptHeader -> AcceptHeader
addToAccept p (ZeroToOne f) (AcceptHeader h) = AcceptHeader (cont h) addToAccept p (ZeroToOne f) (AcceptHeader h) = AcceptHeader (cont h)
where new = cs (show $ contentType p) `append` "; q=" `append` pack (show f) where new = cs (show $ contentType p) `append` "; q=" `append` pack (show f)

View file

@ -6,6 +6,7 @@ packages:
- servant-foreign/ - servant-foreign/
- servant-server/ - servant-server/
extra-deps: extra-deps:
- aeson-compat-0.3.6
- base-compat-0.9.1 - base-compat-0.9.1
- control-monad-omega-0.3.1 - control-monad-omega-0.3.1
- cryptonite-0.6 - cryptonite-0.6