refactor(avs): get rid of awkward signatures and contain AVS api to one module

This commit is contained in:
Steffen Jost 2022-06-30 13:32:30 +02:00
parent 885d268d50
commit a8dc8f6d90
3 changed files with 63 additions and 24 deletions

View File

@ -359,16 +359,12 @@ makeFoundation appSettings''@AppSettings{..} = do
, baseUrlPort = avsPort avsConf
, baseUrlPath = ""
}
avsEnv = mkClientEnv manager avsServer
avsAuth = BasicAuthData
{ basicAuthUsername = avsUser avsConf
, basicAuthPassword = avsPass avsConf
}
(avsPersonSearch :<|> avsPersonStatus) = client avsApi avsAuth
runQuery query = runClientM query $ mkClientEnv manager avsServer
return $ Just AvsQuery
{ avsQueryPerson = liftIO . runQuery . avsPersonSearch
, avsQueryStatus = liftIO . runQuery . avsPersonStatus
}
return . Just $ mkAvsQuery avsAuth avsEnv
$logDebugS "Runtime configuration" $ tshow appSettings'

View File

@ -1,3 +1,4 @@
{-# LANGUAGE GADTs #-}
module Utils.Avs where
@ -10,14 +11,19 @@ import Data.Aeson
import Data.Aeson.Types
import Servant
import Servant.Client.Core (ClientError)
import Servant.Client
-- just to speed up type checking
import qualified Data.Set as Set
import qualified Network.HTTP.Client as HTTP (newManager, defaultManagerSettings)
-- | Like (.:) but attempts parsing with case-insensitve keys as fallback.
-- Taken from Data.Aeson.Filthy, which could somehow not be added as a dependency.
{-
(.:~) :: FromJSON a => Object -> Text -> Parser a -- would be useful for AvsDataPerson, where Case is inconsistent
(.:~) :: FromJSON a => Object -> Text -> Parser a -- would be useful for AvsDataPerson, where Case is inconsistently encoded
o .:~ key = o .: key <|> maybe empty parseJSON go
where go = lookup (Text.toLower key) [(Text.toLower k, v) | (k,v) <- HM.toList o]
-}
@ -128,23 +134,58 @@ deriveJSON defaultOptions
} ''AvsResponseStatus
data AvsQuery = AvsQuery
{ avsQueryPerson :: forall m. MonadIO m => AvsPersonQuery -> m (Either ClientError AvsPersonResponse)
, avsQueryStatus :: forall m. MonadIO m => AvsStatusQuery -> m (Either ClientError AvsStatusResponse)
}
makeLenses_ ''AvsQuery
type AVS = AVSRoute (AVSPersonSearch :<|> AVSPersonStatus)
type AVSAuth = BasicAuth "avs_fradrive" String
type AVSRoute a = AVSAuth :> "FraVSMService" :> "v1" :> a
type AVS = BasicAuth "avs_fradrive" String :> "FraVSMService" :> "v1" :> (AVSPersonSearch :<|> AVSPersonStatus)
type AVSPersonSearch = "PersonSearch" :> ReqBody '[JSON] AvsPersonQuery :> Post '[JSON] AvsPersonResponse
type AVSPersonStatus = "PersonStatus" :> ReqBody '[JSON] AvsStatusQuery :> Post '[JSON] AvsStatusResponse
type AVSPersonStatus = "PersonStatus" :> ReqBody '[JSON] AvsStatusQuery :> Post '[JSON] AvsResponseStatus
avsApi :: Proxy AVS
avsApi = Proxy
{- Somehow the GADT-style declaration is not flexible enough to compile at the location of the function call
data AvsQuery where
AvsQuery :: { avsQueryPerson :: MonadIO m => AvsPersonQuery -> m (Either ClientError AvsPersonResponse)
, avsQueryStatus :: MonadIO m => AvsStatusQuery -> m (Either ClientError AvsResponseStatus)
}
-> AvsQuery
-}
data AvsQuery = AvsQuery
{ avsQueryPerson :: forall m. MonadIO m => AvsPersonQuery -> m (Either ClientError AvsPersonResponse)
, avsQueryStatus :: forall m. MonadIO m => AvsStatusQuery -> m (Either ClientError AvsResponseStatus)
}
makeLenses_ ''AvsQuery
mkAvsQuery :: BasicAuthData -> ClientEnv -> AvsQuery
mkAvsQuery basicAuth cliEnv = AvsQuery
{ avsQueryPerson = \q -> liftIO $ runClientM (rawQueryPerson q) cliEnv
, avsQueryStatus = \q -> liftIO $ runClientM (rawQueryStatus q) cliEnv
}
where
(rawQueryPerson :<|> rawQueryStatus) = client avsApi basicAuth
-- DEMO to check that it types here instead of waiting for Application to be compiled
run :: IO ()
run = do
let (_avsPersonSearch :<|> avsPersonStatus) = client avsApi avsAuth
manager' <- HTTP.newManager HTTP.defaultManagerSettings
let query = avsPersonStatus $ AvsStatusQuery $ Set.singleton 123
res <- runClientM query (mkClientEnv manager' avsServer)
case res of
Left err -> putStrLn $ "Error: " ++ tshow err
--Right resp -> do
Right (AvsResponseStatus resp) -> do
print resp
where
avsServer :: BaseUrl
avsServer = BaseUrl
{ baseUrlScheme = Https
, baseUrlHost = "skytest.fra.fraport.de"
, baseUrlPort = 80
, baseUrlPath = ""
}
avsAuth = BasicAuthData "foo" "bar"

View File

@ -513,6 +513,8 @@ spec = do
[ eqLaws, ordLaws, showLaws, showReadLaws, boundedEnumLaws, finiteLaws, pathPieceLaws, jsonLaws, jsonKeyLaws, persistFieldLaws, binaryLaws, httpApiDataLaws ]
lawsCheckHspec (Proxy @LmsStatus)
[ eqLaws, ordLaws, showLaws, showReadLaws, jsonLaws ]
lawsCheckHspec (Proxy @AvsResponseStatus)
[ eqLaws, showLaws, showReadLaws, jsonLaws]
describe "TermIdentifier" $ do
it "has compatible encoding/decoding to/from Text" . property $