module Network.API.Builder.API (
API
, APIT
, execAPI
, runAPI
, runRoute
, sendRoute
, routeResponse
, routeRequest
, liftExcept
, liftEither
, liftManager
, liftBuilder
, liftState
, name
, baseURL
, customizeRoute
, customizeRequest ) where
import Network.API.Builder.Builder
import Network.API.Builder.Error
import Network.API.Builder.Receive
import Network.API.Builder.Routes
import Network.API.Builder.Send
import Data.Bifunctor
import Control.Exception
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Except
import Control.Monad.Trans.Reader
import Control.Monad.Trans.State
import Data.ByteString.Lazy (ByteString)
import Data.Text (Text)
import Network.HTTP.Client
import Network.HTTP.Client.TLS
type API s e a = APIT s e IO a
type APIT s e m a = ExceptT (APIError e) (ReaderT Manager (StateT Builder (StateT s m))) a
liftExcept :: Monad m => ExceptT (APIError e) (ReaderT Manager (StateT Builder (StateT s m))) a -> APIT s e m a
liftExcept = id
liftEither :: Monad m => ExceptT (APIError e) (ReaderT Manager (StateT Builder (StateT s m))) a -> APIT s e m a
liftEither = id
liftManager :: Monad m => ReaderT Manager (StateT Builder (StateT s m)) a -> APIT s e m a
liftManager = lift
liftBuilder :: Monad m => StateT Builder (StateT s m) a -> APIT s e m a
liftBuilder = lift . lift
liftState :: Monad m => StateT s m a -> APIT s e m a
liftState = lift . lift . lift
execAPI :: MonadIO m
=> Builder
-> s
-> APIT s e m a
-> m (Either (APIError e) a)
execAPI b s api = do
m <- liftIO $ newManager tlsManagerSettings
(res, _, _) <- runAPI b m s api
return res
runAPI :: MonadIO m
=> Builder
-> Manager
-> s
-> APIT s e m a
-> m (Either (APIError e) a, Builder, s)
runAPI b m s api = do
((res, b'), s') <- runStateT (runStateT (runReaderT (runExceptT api) m) b) s
return (res, b', s')
runRoute :: (Receivable a, ErrorReceivable e, MonadIO m) => Route -> APIT s e m a
runRoute = sendRoute ()
routeResponse :: (MonadIO m, ErrorReceivable e) => Route -> APIT s e m (Response ByteString)
routeResponse = sendRoute ()
eitherOr :: Maybe a -> b -> Either b a
a `eitherOr` b =
case a of
Just x -> Right x
Nothing -> Left b
sendRoute :: (MonadIO m, Sendable t, ErrorReceivable e, Receivable r) => t -> Route -> APIT s e m r
sendRoute s r = do
builder <- liftBuilder get
manager <- liftManager ask
req <- ExceptT $ return $ send builder r s `eitherOr` InvalidURLError
response <- liftIO $ try $ httpLbs req manager
res <- ExceptT $ return $ first HTTPError response
ExceptT $ return $ receive res
routeRequest :: Builder -> Route -> Maybe Request
routeRequest b route = send b route ()
name :: Monad m => Text -> APIT s e m ()
name t = liftBuilder $ modify (\b -> b { _name = t })
baseURL :: Monad m => Text -> APIT s e m ()
baseURL t = liftBuilder $ modify (\b -> b { _baseURL = t })
customizeRoute :: Monad m => (Route -> Route) -> APIT s e m ()
customizeRoute f = liftBuilder $ modify (\b -> b { _customizeRoute = f })
customizeRequest :: Monad m => (Request -> Request) -> APIT s e m ()
customizeRequest f = liftBuilder $ modify (\b -> b { _customizeRequest = f })