servant/servant-client-core/src/Servant/Client/Core/Internal/RunClient.hs

61 lines
2.3 KiB
Haskell
Raw Normal View History

2017-09-07 22:38:31 +02:00
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
2017-09-14 15:53:51 +02:00
{-# LANGUAGE OverloadedStrings #-}
2017-09-13 01:49:55 +02:00
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
2017-09-13 17:05:48 +02:00
-- | Types for possible backends to run client-side `Request` queries
2017-09-13 18:36:20 +02:00
module Servant.Client.Core.Internal.RunClient where
2018-06-30 21:17:08 +02:00
import Prelude ()
2017-09-15 20:57:03 +02:00
import Prelude.Compat
2017-09-14 15:53:51 +02:00
2018-06-30 21:17:08 +02:00
import Control.Monad
(unless)
import Control.Monad.Free
(Free (..), liftF)
import Data.Foldable
(toList)
import Data.Proxy
(Proxy)
2017-09-13 01:49:55 +02:00
import qualified Data.Text as T
2018-06-30 21:17:08 +02:00
import Network.HTTP.Media
(MediaType, matches, parseAccept, (//))
import Servant.API
(MimeUnrender, contentTypes, mimeUnrender)
2018-03-11 13:03:27 +01:00
import Servant.Client.Core.Internal.ClientF
2018-06-30 21:17:08 +02:00
import Servant.Client.Core.Internal.Request
(GenResponse (..), Request, Response, ServantError (..),
StreamingResponse)
2018-03-11 15:50:14 +01:00
class Monad m => RunClient m where
2017-09-13 01:49:55 +02:00
-- | How to make a request.
2017-09-07 22:38:31 +02:00
runRequest :: Request -> m Response
2017-10-25 02:12:21 +02:00
streamingRequest :: Request -> m StreamingResponse
2017-09-15 20:57:03 +02:00
throwServantError :: ServantError -> m a
2017-09-13 01:49:55 +02:00
checkContentTypeHeader :: RunClient m => Response -> m MediaType
checkContentTypeHeader response =
case lookup "Content-Type" $ toList $ responseHeaders response of
2017-09-14 15:53:51 +02:00
Nothing -> return $ "application"//"octet-stream"
2017-09-13 01:49:55 +02:00
Just t -> case parseAccept t of
2017-09-15 20:57:03 +02:00
Nothing -> throwServantError $ InvalidContentTypeHeader response
2017-09-14 15:53:51 +02:00
Just t' -> return t'
2017-09-13 01:49:55 +02:00
decodedAs :: forall ct a m. (MimeUnrender ct a, RunClient m)
=> Response -> Proxy ct -> m a
decodedAs response contentType = do
responseContentType <- checkContentTypeHeader response
unless (any (matches responseContentType) accept) $
2017-09-15 20:57:03 +02:00
throwServantError $ UnsupportedContentType responseContentType response
2017-09-13 01:49:55 +02:00
case mimeUnrender contentType $ responseBody response of
2017-09-15 20:57:03 +02:00
Left err -> throwServantError $ DecodeFailure (T.pack err) response
2017-09-13 01:49:55 +02:00
Right val -> return val
where
accept = toList $ contentTypes contentType
2018-03-11 13:03:27 +01:00
instance ClientF ~ f => RunClient (Free f) where
runRequest req = liftF (RunRequest req id)
streamingRequest req = liftF (StreamingRequest req id)
throwServantError = liftF . Throw