api-maker-0.1.0.0: src/Network/HTTP/ApiMaker/Class.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# 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 (..)
) where
import Control.Monad.Base
import Control.Monad.Except
import Control.Monad.Trans.Reader
import Control.Monad.Trans.State
import Data.Kind (Type)
import Data.Proxy
import Network.HTTP.Req
import Network.HTTP.ApiMaker.SessionState
-- | Class definition for a 'Request'. Every request should implement this, the rest is then handled by the library. See 'Network.HTTP.ApiMaker.Ops.mkReq' to create a request, the functions
-- 'Network.HTTP.ApiMaker.Ops.mkReqM' and 'Network.HTTP.ApiMaker.Ops.runRequests' to build a 'SafeReqM' monad that shares the same state, session and configuration, and finally
-- 'Network.HTTP.ApiMaker.Ops.runReqM', 'Network.HTTP.ApiMaker.Ops.runSessReqM', 'Network.HTTP.ApiMaker.Ops.runReqWithParamsM' and 'Network.HTTP.ApiMaker.Ops.runSessReqWithParamsM' to run the monad.
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
-- type Protocol r :: Scheme
method :: cfg -> r -> Method r
url :: cfg -> r -> Url 'Https -- (Protocol r)
body :: cfg -> r -> Body r
response :: cfg -> r -> Proxy (Response r)
option :: cfg -> r -> Option 'Https -- (Protocol r)
process :: (MonadHttp m, SessionState st) => cfg -> r -> Response r -> StateT st m (Output r)
-- Type safe request
-- | Configuration that is passed from request to request to hold the session and default https header options. It also holds a user defined configuration.
data Config cfg = Config
{ httpConfig :: HttpConfig
, apiDefaultParameters :: [Option 'Https]
, apiConfig :: cfg
}
type SafeReqSt sessionState cfg a = StateT sessionState (SafeReqM cfg) a
type SafeReq cfg a = SafeReqSt Session cfg a
-- | Safe request, e.g. all errors are caught and tured into exceptions.
newtype SafeReqM cfg a =
SafeReqM (ExceptT HttpException (ReaderT (Config cfg) IO) a)
deriving (Functor, Applicative, Monad, MonadIO)
askConfig :: SafeReqM cfg (Config cfg)
askConfig = SafeReqM (lift ask)
askApiConfig :: SafeReqM cfg cfg
askApiConfig = apiConfig <$> SafeReqM (lift ask)
instance MonadBase IO (SafeReqM cfg) where
liftBase = liftIO
instance MonadHttp (SafeReqM cfg) where
handleHttpException = SafeReqM . throwError
getHttpConfig = httpConfig <$> SafeReqM (lift ask)
-- | Safely run the request monad.
runSafeReqM ::
MonadIO m
=> Config cfg -- ^ Config including 'HttpConfig' to use
-> SafeReqM cfg a -- ^ Computation to run
-> m (Either HttpException a)
runSafeReqM config (SafeReqM m) = liftIO (runReaderT (runExceptT m) config)