{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
module Network.HTTP.ApiMaker.Class
( Request(..)
, Config (..)
, SessionState (..)
, Session(..)
, emptySession
, runSafeReqM
, askConfig
, askApiConfig
, SafeReqSt
, SafeReq
, SafeReqM (..)
, SafeException (..)
, throwUserException
) where
import Control.Exception
import Control.Monad.Base
import Control.Monad.Except
import Control.Monad.Trans.Reader
import Control.Monad.Trans.State
import Data.Dynamic
import Data.Kind (Type)
import Data.Proxy
import qualified Network.HTTP.Client as C
import Network.HTTP.Req
import Network.HTTP.ApiMaker.SessionState
class (HttpMethod (Method r), HttpBody (Body r), HttpResponse (Response r), HttpBodyAllowed (AllowsBody (Method r)) (ProvidesBody (Body r))) =>
Request cfg r
where
type Method r :: Type
type Body r :: Type
type Response r :: Type
type Output r :: Type
method :: cfg -> r -> Method r
url :: cfg -> r -> Url 'Https
body :: cfg -> r -> Body r
response :: cfg -> r -> Proxy (Response r)
option :: cfg -> r -> IO (Option 'Https)
requestModifier :: cfg -> r -> C.Request -> IO C.Request
requestModifier cfg
_ r
_ = Request -> IO Request
forall (m :: Type -> Type) a. Monad m => a -> m a
return
process :: (MonadHttp m, MonadError SafeException m, SessionState st) => cfg -> r -> Response r -> StateT st m (Output r)
data Config cfg = Config
{ Config cfg -> HttpConfig
httpConfig :: HttpConfig
, Config cfg -> [Option 'Https]
apiDefaultParameters :: [Option 'Https]
, Config cfg -> cfg
apiConfig :: cfg
}
type SafeReqSt sessionState cfg a = StateT sessionState (SafeReqM cfg) a
type SafeReq cfg a = SafeReqSt Session cfg a
data SafeException
= ReqException HttpException
| forall e. (Typeable e, Exception e) =>
SafeUserException e
instance Exception SafeException
instance Show SafeException where
show :: SafeException -> String
show (ReqException HttpException
e) = HttpException -> String
forall a. Show a => a -> String
show HttpException
e
show (SafeUserException e
e) = e -> String
forall a. Show a => a -> String
show e
e
newtype SafeReqM cfg a =
SafeReqM (ExceptT SafeException (ReaderT (Config cfg) IO) a)
deriving (a -> SafeReqM cfg b -> SafeReqM cfg a
(a -> b) -> SafeReqM cfg a -> SafeReqM cfg b
(forall a b. (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b)
-> (forall a b. a -> SafeReqM cfg b -> SafeReqM cfg a)
-> Functor (SafeReqM cfg)
forall a b. a -> SafeReqM cfg b -> SafeReqM cfg a
forall a b. (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b
forall cfg a b. a -> SafeReqM cfg b -> SafeReqM cfg a
forall cfg a b. (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b
forall (f :: Type -> Type).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> SafeReqM cfg b -> SafeReqM cfg a
$c<$ :: forall cfg a b. a -> SafeReqM cfg b -> SafeReqM cfg a
fmap :: (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b
$cfmap :: forall cfg a b. (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b
Functor, Functor (SafeReqM cfg)
a -> SafeReqM cfg a
Functor (SafeReqM cfg)
-> (forall a. a -> SafeReqM cfg a)
-> (forall a b.
SafeReqM cfg (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b)
-> (forall a b c.
(a -> b -> c)
-> SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg c)
-> (forall a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b)
-> (forall a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg a)
-> Applicative (SafeReqM cfg)
SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b
SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg a
SafeReqM cfg (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b
(a -> b -> c) -> SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg c
forall cfg. Functor (SafeReqM cfg)
forall a. a -> SafeReqM cfg a
forall cfg a. a -> SafeReqM cfg a
forall a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg a
forall a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b
forall a b.
SafeReqM cfg (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b
forall cfg a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg a
forall cfg a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b
forall cfg a b.
SafeReqM cfg (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b
forall a b c.
(a -> b -> c) -> SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg c
forall cfg a b c.
(a -> b -> c) -> SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg c
forall (f :: Type -> Type).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg a
$c<* :: forall cfg a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg a
*> :: SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b
$c*> :: forall cfg a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b
liftA2 :: (a -> b -> c) -> SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg c
$cliftA2 :: forall cfg a b c.
(a -> b -> c) -> SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg c
<*> :: SafeReqM cfg (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b
$c<*> :: forall cfg a b.
SafeReqM cfg (a -> b) -> SafeReqM cfg a -> SafeReqM cfg b
pure :: a -> SafeReqM cfg a
$cpure :: forall cfg a. a -> SafeReqM cfg a
$cp1Applicative :: forall cfg. Functor (SafeReqM cfg)
Applicative, Applicative (SafeReqM cfg)
a -> SafeReqM cfg a
Applicative (SafeReqM cfg)
-> (forall a b.
SafeReqM cfg a -> (a -> SafeReqM cfg b) -> SafeReqM cfg b)
-> (forall a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b)
-> (forall a. a -> SafeReqM cfg a)
-> Monad (SafeReqM cfg)
SafeReqM cfg a -> (a -> SafeReqM cfg b) -> SafeReqM cfg b
SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b
forall cfg. Applicative (SafeReqM cfg)
forall a. a -> SafeReqM cfg a
forall cfg a. a -> SafeReqM cfg a
forall a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b
forall a b.
SafeReqM cfg a -> (a -> SafeReqM cfg b) -> SafeReqM cfg b
forall cfg a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b
forall cfg a b.
SafeReqM cfg a -> (a -> SafeReqM cfg b) -> SafeReqM cfg b
forall (m :: Type -> Type).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: a -> SafeReqM cfg a
$creturn :: forall cfg a. a -> SafeReqM cfg a
>> :: SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b
$c>> :: forall cfg a b. SafeReqM cfg a -> SafeReqM cfg b -> SafeReqM cfg b
>>= :: SafeReqM cfg a -> (a -> SafeReqM cfg b) -> SafeReqM cfg b
$c>>= :: forall cfg a b.
SafeReqM cfg a -> (a -> SafeReqM cfg b) -> SafeReqM cfg b
$cp1Monad :: forall cfg. Applicative (SafeReqM cfg)
Monad, Monad (SafeReqM cfg)
Monad (SafeReqM cfg)
-> (forall a. IO a -> SafeReqM cfg a) -> MonadIO (SafeReqM cfg)
IO a -> SafeReqM cfg a
forall cfg. Monad (SafeReqM cfg)
forall a. IO a -> SafeReqM cfg a
forall cfg a. IO a -> SafeReqM cfg a
forall (m :: Type -> Type).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
liftIO :: IO a -> SafeReqM cfg a
$cliftIO :: forall cfg a. IO a -> SafeReqM cfg a
$cp1MonadIO :: forall cfg. Monad (SafeReqM cfg)
MonadIO)
askConfig :: SafeReqM cfg (Config cfg)
askConfig :: SafeReqM cfg (Config cfg)
askConfig = ExceptT SafeException (ReaderT (Config cfg) IO) (Config cfg)
-> SafeReqM cfg (Config cfg)
forall cfg a.
ExceptT SafeException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
SafeReqM (ReaderT (Config cfg) IO (Config cfg)
-> ExceptT SafeException (ReaderT (Config cfg) IO) (Config cfg)
forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift ReaderT (Config cfg) IO (Config cfg)
forall (m :: Type -> Type) r. Monad m => ReaderT r m r
ask)
askApiConfig :: SafeReqM cfg cfg
askApiConfig :: SafeReqM cfg cfg
askApiConfig = Config cfg -> cfg
forall cfg. Config cfg -> cfg
apiConfig (Config cfg -> cfg)
-> SafeReqM cfg (Config cfg) -> SafeReqM cfg cfg
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> ExceptT SafeException (ReaderT (Config cfg) IO) (Config cfg)
-> SafeReqM cfg (Config cfg)
forall cfg a.
ExceptT SafeException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
SafeReqM (ReaderT (Config cfg) IO (Config cfg)
-> ExceptT SafeException (ReaderT (Config cfg) IO) (Config cfg)
forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift ReaderT (Config cfg) IO (Config cfg)
forall (m :: Type -> Type) r. Monad m => ReaderT r m r
ask)
instance MonadBase IO (SafeReqM cfg) where
liftBase :: IO α -> SafeReqM cfg α
liftBase = IO α -> SafeReqM cfg α
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO
instance MonadHttp (SafeReqM cfg) where
handleHttpException :: HttpException -> SafeReqM cfg a
handleHttpException = ExceptT SafeException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
forall cfg a.
ExceptT SafeException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
SafeReqM (ExceptT SafeException (ReaderT (Config cfg) IO) a
-> SafeReqM cfg a)
-> (HttpException
-> ExceptT SafeException (ReaderT (Config cfg) IO) a)
-> HttpException
-> SafeReqM cfg a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SafeException -> ExceptT SafeException (ReaderT (Config cfg) IO) a
forall e (m :: Type -> Type) a. MonadError e m => e -> m a
throwError (SafeException
-> ExceptT SafeException (ReaderT (Config cfg) IO) a)
-> (HttpException -> SafeException)
-> HttpException
-> ExceptT SafeException (ReaderT (Config cfg) IO) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HttpException -> SafeException
ReqException
getHttpConfig :: SafeReqM cfg HttpConfig
getHttpConfig = Config cfg -> HttpConfig
forall cfg. Config cfg -> HttpConfig
httpConfig (Config cfg -> HttpConfig)
-> SafeReqM cfg (Config cfg) -> SafeReqM cfg HttpConfig
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> ExceptT SafeException (ReaderT (Config cfg) IO) (Config cfg)
-> SafeReqM cfg (Config cfg)
forall cfg a.
ExceptT SafeException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
SafeReqM (ReaderT (Config cfg) IO (Config cfg)
-> ExceptT SafeException (ReaderT (Config cfg) IO) (Config cfg)
forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift ReaderT (Config cfg) IO (Config cfg)
forall (m :: Type -> Type) r. Monad m => ReaderT r m r
ask)
instance MonadError SafeException (SafeReqM cfg) where
throwError :: SafeException -> SafeReqM cfg a
throwError = ExceptT SafeException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
forall cfg a.
ExceptT SafeException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
SafeReqM (ExceptT SafeException (ReaderT (Config cfg) IO) a
-> SafeReqM cfg a)
-> (SafeException
-> ExceptT SafeException (ReaderT (Config cfg) IO) a)
-> SafeException
-> SafeReqM cfg a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SafeException -> ExceptT SafeException (ReaderT (Config cfg) IO) a
forall e (m :: Type -> Type) a. MonadError e m => e -> m a
throwError (SafeException
-> ExceptT SafeException (ReaderT (Config cfg) IO) a)
-> (SafeException -> SafeException)
-> SafeException
-> ExceptT SafeException (ReaderT (Config cfg) IO) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SafeException -> SafeException
forall e. (Typeable e, Exception e) => e -> SafeException
SafeUserException
catchError :: SafeReqM cfg a
-> (SafeException -> SafeReqM cfg a) -> SafeReqM cfg a
catchError SafeReqM cfg a
c SafeException -> SafeReqM cfg a
h = do
Config cfg
cfg <- SafeReqM cfg (Config cfg)
forall cfg. SafeReqM cfg (Config cfg)
askConfig
Either SafeException a
res <- Config cfg
-> SafeReqM cfg a -> SafeReqM cfg (Either SafeException a)
forall (m :: Type -> Type) cfg a.
MonadIO m =>
Config cfg -> SafeReqM cfg a -> m (Either SafeException a)
runSafeReqM Config cfg
cfg SafeReqM cfg a
c
case Either SafeException a
res of
Left SafeException
ex -> SafeException -> SafeReqM cfg a
h SafeException
ex
Right{} -> ExceptT SafeException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
forall cfg a.
ExceptT SafeException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
SafeReqM (ExceptT SafeException (ReaderT (Config cfg) IO) a
-> SafeReqM cfg a)
-> ExceptT SafeException (ReaderT (Config cfg) IO) a
-> SafeReqM cfg a
forall a b. (a -> b) -> a -> b
$ ReaderT (Config cfg) IO (Either SafeException a)
-> ExceptT SafeException (ReaderT (Config cfg) IO) a
forall e (m :: Type -> Type) a. m (Either e a) -> ExceptT e m a
ExceptT (ReaderT (Config cfg) IO (Either SafeException a)
-> ExceptT SafeException (ReaderT (Config cfg) IO) a)
-> ReaderT (Config cfg) IO (Either SafeException a)
-> ExceptT SafeException (ReaderT (Config cfg) IO) a
forall a b. (a -> b) -> a -> b
$ Either SafeException a
-> ReaderT (Config cfg) IO (Either SafeException a)
forall (m :: Type -> Type) a. Monad m => a -> m a
return Either SafeException a
res
throwUserException :: (MonadError SafeException m, Exception e) => e -> m a
throwUserException :: e -> m a
throwUserException = SafeException -> m a
forall e (m :: Type -> Type) a. MonadError e m => e -> m a
throwError (SafeException -> m a) -> (e -> SafeException) -> e -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> SafeException
forall e. (Typeable e, Exception e) => e -> SafeException
SafeUserException
runSafeReqM ::
MonadIO m
=> Config cfg
-> SafeReqM cfg a
-> m (Either SafeException a)
runSafeReqM :: Config cfg -> SafeReqM cfg a -> m (Either SafeException a)
runSafeReqM Config cfg
config (SafeReqM ExceptT SafeException (ReaderT (Config cfg) IO) a
m) = IO (Either SafeException a) -> m (Either SafeException a)
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (ReaderT (Config cfg) IO (Either SafeException a)
-> Config cfg -> IO (Either SafeException a)
forall r (m :: Type -> Type) a. ReaderT r m a -> r -> m a
runReaderT (ExceptT SafeException (ReaderT (Config cfg) IO) a
-> ReaderT (Config cfg) IO (Either SafeException a)
forall e (m :: Type -> Type) a. ExceptT e m a -> m (Either e a)
runExceptT ExceptT SafeException (ReaderT (Config cfg) IO) a
m) Config cfg
config)