packages feed

api-maker 0.1.0.0 → 0.1.0.6

raw patch · 5 files changed

+94/−18 lines, 5 filesdep +easy-loggerdep +http-api-dataPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: easy-logger, http-api-data

API changes (from Hackage documentation)

+ Network.HTTP.ApiMaker.Class: ReqException :: HttpException -> SafeException
+ Network.HTTP.ApiMaker.Class: SafeUserException :: e -> SafeException
+ Network.HTTP.ApiMaker.Class: data SafeException
+ Network.HTTP.ApiMaker.Class: instance Control.Monad.Error.Class.MonadError Network.HTTP.ApiMaker.Class.SafeException (Network.HTTP.ApiMaker.Class.SafeReqM cfg)
+ Network.HTTP.ApiMaker.Class: instance GHC.Exception.Type.Exception Network.HTTP.ApiMaker.Class.SafeException
+ Network.HTTP.ApiMaker.Class: instance GHC.Show.Show Network.HTTP.ApiMaker.Class.SafeException
+ Network.HTTP.ApiMaker.Class: requestModifier :: Request cfg r => cfg -> r -> Request -> IO Request
+ Network.HTTP.ApiMaker.Class: throwUserException :: (MonadError SafeException m, Exception e) => e -> m a
+ Network.HTTP.ApiMaker.Logging: disableRequestLogging :: IO ()
+ Network.HTTP.ApiMaker.Logging: enableRequestLogging :: LogDestination -> IO ()
+ Network.HTTP.ApiMaker.Ops: maybeQueryParam :: (Monoid param, QueryParam param, ToHttpApiData a) => Text -> Maybe a -> param
- Network.HTTP.ApiMaker.Class: SafeReqM :: ExceptT HttpException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
+ Network.HTTP.ApiMaker.Class: SafeReqM :: ExceptT SafeException (ReaderT (Config cfg) IO) a -> SafeReqM cfg a
- Network.HTTP.ApiMaker.Class: option :: Request cfg r => cfg -> r -> Option 'Https
+ Network.HTTP.ApiMaker.Class: option :: Request cfg r => cfg -> r -> IO (Option 'Https)
- Network.HTTP.ApiMaker.Class: process :: (Request cfg r, MonadHttp m, SessionState st) => cfg -> r -> Response r -> StateT st m (Output r)
+ Network.HTTP.ApiMaker.Class: process :: (Request cfg r, MonadHttp m, MonadError SafeException m, SessionState st) => cfg -> r -> Response r -> StateT st m (Output r)
- Network.HTTP.ApiMaker.Class: runSafeReqM :: MonadIO m => Config cfg -> SafeReqM cfg a -> m (Either HttpException a)
+ Network.HTTP.ApiMaker.Class: runSafeReqM :: MonadIO m => Config cfg -> SafeReqM cfg a -> m (Either SafeException a)
- Network.HTTP.ApiMaker.Ops: runReqM :: MonadIO m => SafeReqM () a -> m (Either HttpException a)
+ Network.HTTP.ApiMaker.Ops: runReqM :: MonadIO m => SafeReqM () a -> m (Either SafeException a)
- Network.HTTP.ApiMaker.Ops: runReqWithParamsM :: MonadIO m => [Option 'Https] -> SafeReqM () a -> m (Either HttpException a)
+ Network.HTTP.ApiMaker.Ops: runReqWithParamsM :: MonadIO m => [Option 'Https] -> SafeReqM () a -> m (Either SafeException a)
- Network.HTTP.ApiMaker.Ops: runSessReqM :: MonadIO m => cfg -> SafeReqM cfg a -> m (Either HttpException a)
+ Network.HTTP.ApiMaker.Ops: runSessReqM :: MonadIO m => cfg -> SafeReqM cfg a -> m (Either SafeException a)
- Network.HTTP.ApiMaker.Ops: runSessReqWithParamsM :: MonadIO m => [Option 'Https] -> cfg -> SafeReqM cfg a -> m (Either HttpException a)
+ Network.HTTP.ApiMaker.Ops: runSessReqWithParamsM :: MonadIO m => [Option 'Https] -> cfg -> SafeReqM cfg a -> m (Either SafeException a)

Files

api-maker.cabal view
@@ -1,13 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.2.+-- This file has been generated from package.yaml by hpack version 0.34.4. -- -- see: https://github.com/sol/hpack------ hash: 6a6fa3f0f379eade6020b6c856c601ee0501ed76dedb9ef47f70a2a62406e38c  name:           api-maker-version:        0.1.0.0+version:        0.1.0.6 synopsis:       Package to make APIs description:    Please see the README on GitHub at <https://github.com/schnecki/api-maker#readme> category:       Web@@ -32,6 +30,7 @@       ApiMaker       Network.HTTP.ApiMaker.Class       Network.HTTP.ApiMaker.HeaderContent+      Network.HTTP.ApiMaker.Logging       Network.HTTP.ApiMaker.Ops       Network.HTTP.ApiMaker.SessionState   other-modules:@@ -44,6 +43,8 @@     , base >=4.7 && <5     , bytestring     , containers+    , easy-logger >=0.1.0.6+    , http-api-data     , http-client     , http-client-tls     , http-types@@ -58,7 +59,8 @@     ghc-options: -fno-warn-incomplete-patterns     cpp-options: -DType=*   if impl(ghc >= 8.6)-    default-extensions: NoStarIsType+    default-extensions:+        NoStarIsType   default-language: Haskell2010  test-suite api-maker-test@@ -75,6 +77,8 @@     , base >=4.7 && <5     , bytestring     , containers+    , easy-logger >=0.1.0.6+    , http-api-data     , http-client     , http-client-tls     , http-types
src/ApiMaker.hs view
@@ -3,6 +3,7 @@     ) where  import           Network.HTTP.ApiMaker.Class         as R+import           Network.HTTP.ApiMaker.Logging       as R import           Network.HTTP.ApiMaker.Ops           as R  import           Network.HTTP.ApiMaker.HeaderContent as R
src/Network/HTTP/ApiMaker/Class.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE CPP                        #-} {-# LANGUAGE DataKinds                  #-} {-# LANGUAGE DeriveFunctor              #-}+{-# LANGUAGE ExistentialQuantification  #-} {-# LANGUAGE FlexibleContexts           #-} {-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}@@ -22,14 +23,19 @@   , 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@@ -50,8 +56,10 @@   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)+  option   :: cfg -> r -> IO (Option 'Https) -- (Protocol r)+  requestModifier :: cfg -> r -> C.Request -> IO C.Request+  requestModifier _ _ = return+  process  :: (MonadHttp m, MonadError SafeException m, SessionState st) => cfg -> r -> Response r -> StateT st m (Output r)   -- Type safe request@@ -63,12 +71,27 @@   , apiConfig            :: cfg   } +-- | Safe request monad with customized session state `sessionState`, Config `cfg` and result `a`. type SafeReqSt sessionState cfg a = StateT sessionState (SafeReqM cfg) a++-- | Safe request monad with predetermined @Session@, config `cfg` and result `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 (ReqException e)      = show e+  show (SafeUserException e) = show e++ -- | Safe request, e.g. all errors are caught and tured into exceptions. newtype SafeReqM cfg a =-  SafeReqM (ExceptT HttpException (ReaderT (Config cfg) IO) a)+  SafeReqM (ExceptT SafeException (ReaderT (Config cfg) IO) a)   deriving (Functor, Applicative, Monad, MonadIO)  askConfig :: SafeReqM cfg (Config cfg)@@ -81,15 +104,30 @@   liftBase = liftIO  instance MonadHttp (SafeReqM cfg) where-  handleHttpException = SafeReqM . throwError+  handleHttpException = SafeReqM . throwError . ReqException   getHttpConfig = httpConfig <$> SafeReqM (lift ask) +instance MonadError SafeException (SafeReqM cfg) where+  throwError = SafeReqM . throwError . SafeUserException+  catchError c h = do+    cfg <- askConfig+    res <- runSafeReqM cfg c+    case res of+      Left ex -> h ex+      Right{} -> SafeReqM $ ExceptT $ return res+++-- | Throw an Exception to the `SafeReqM` Monad.+throwUserException :: (MonadError SafeException m, Exception e) => e -> m a+throwUserException = throwError . SafeUserException++ -- | 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)+  -> m (Either SafeException a) runSafeReqM config (SafeReqM m) = liftIO (runReaderT (runExceptT m) config)  
+ src/Network/HTTP/ApiMaker/Logging.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE TemplateHaskell #-}+module Network.HTTP.ApiMaker.Logging+    ( enableRequestLogging+    , disableRequestLogging+    ) where++import           EasyLogger++enableRequestLogging :: LogDestination -> IO ()+enableRequestLogging = $(initLogger)++disableRequestLogging :: IO ()+disableRequestLogging = $(finalizeLogger)++
src/Network/HTTP/ApiMaker/Ops.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE DataKinds         #-} {-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE KindSignatures    #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell   #-} module Network.HTTP.ApiMaker.Ops   ( mkReq   , runRequests@@ -10,6 +12,7 @@   , runReqWithParamsM   , runSessReqM   , runSessReqWithParamsM+  , maybeQueryParam   ) where  import           Control.Lens@@ -17,26 +20,29 @@ import           Control.Monad.Trans.State import qualified Data.ByteString.Char8       as B import           Data.List                   (find)+import qualified Data.Text                   as T+import           EasyLogger import qualified Network.HTTP.Client         as C import           Network.HTTP.Req+import           Web.HttpApiData  import           Network.HTTP.ApiMaker.Class   -- | Prepare to run requests.-runReqM :: (MonadIO m) => SafeReqM () a -> m (Either HttpException a)+runReqM :: (MonadIO m) => SafeReqM () a -> m (Either SafeException a) runReqM = runSafeReqM (Config defaultHttpConfig [] ())  -- | Prepare to run requests with addional header options.-runReqWithParamsM :: (MonadIO m) => [Option 'Https] -> SafeReqM () a -> m (Either HttpException a)+runReqWithParamsM :: (MonadIO m) => [Option 'Https] -> SafeReqM () a -> m (Either SafeException a) runReqWithParamsM params = runSafeReqM (Config defaultHttpConfig params ())  -- | Prepare to run request with config.-runSessReqM :: (MonadIO m) => cfg -> SafeReqM cfg a -> m (Either HttpException a)+runSessReqM :: (MonadIO m) => cfg -> SafeReqM cfg a -> m (Either SafeException a) runSessReqM cfg = runSafeReqM (Config defaultHttpConfig [] cfg)  -- | Prepare to run request with config and additional header options.-runSessReqWithParamsM :: (MonadIO m) => [Option 'Https] -> cfg -> SafeReqM cfg a -> m (Either HttpException a)+runSessReqWithParamsM :: (MonadIO m) => [Option 'Https] -> cfg -> SafeReqM cfg a -> m (Either SafeException a) runSessReqWithParamsM params cfg = runSafeReqM (Config defaultHttpConfig params cfg)  @@ -57,16 +63,20 @@   session <- get   cfg <- lift askConfig   apiCfg <- lift askApiConfig--  let ops = option apiCfg r <> mkSessionOps session <> mconcat (apiDefaultParameters cfg)-  -- liftIO $ putStrLn $ "Running a request to " <> show (url r)-  resp <- lift $ req (method apiCfg r) (url apiCfg r) (body apiCfg r) (response apiCfg r) ops+  opsReq <- liftIO $ option apiCfg r+  let ops = opsReq <> mkSessionOps session <> mconcat (apiDefaultParameters cfg)+  let logging request' = do+        request <- liftIO $ requestModifier apiCfg r request'+        liftIO $ $(logInfo) $ "API Request: " <> T.pack (show request)+        return request+  resp <- lift $ reqCb (method apiCfg r) (url apiCfg r) (body apiCfg r) (response apiCfg r) ops logging   updateSession r resp   process apiCfg r resp   where     mkSessionOps session =       maybe mempty cookieJar (session ^. cookieJarData) <> header "Cookie" (B.intercalate ";" (mkSessionCookie session ++ mkCsrfCookie session)) <> mkCsrfHeader session + updateSession :: (Request cfg request, SessionState st) => request -> Response request -> SafeReqSt st cfg () updateSession _ resp =   let cookies = C.destroyCookieJar $ responseCookieJar resp@@ -92,3 +102,11 @@   case st ^. csrfToken of     Nothing   -> mempty     Just csrf -> header "X-XSRF-TOKEN" csrf+++-- | Create a request parameter only if the value is @Just@. For @Nothing@ the parameter is not present at all in the request.+maybeQueryParam :: (Monoid param, QueryParam param, ToHttpApiData a) => T.Text -> Maybe a -> param+maybeQueryParam _ Nothing  = mempty+maybeQueryParam n (Just x) = n =: x++