transactionTemplate :: a -> m Builder
-- This is our authentication request
data AuthAPI = AuthAPI {
_aapi_user :: Text
,_aapi_pass :: Text
} deriving
-- Auth Builder
genAuthBuilder :: FilePath -> B.ByteString -> IO (StateT AuthAPI IO Builder)
genAuthBuilder baseDir templName = do
hs <- load baseDir ("auth" ## authSplice)
return $ fst . fromJust $ C.renderTemplate hs templName -- C is alias for Heist.Compiled
-- This part could be automated by reading from AuthAPI data type using some kind of generic or TH mechanism?
authSpliceH :: Monad n => RuntimeSplice n AuthAPI -> C.Splice n
authSpliceH = C.withSplices C.runChildren $ do
"user" ## (C.pureSplice . C.textSplice $ _aapi_user) -- first argument comes from: Prelude.drop 6 "_aapi_user"
"pass" ## (C.pureSplice . C.textSplice $ _aapi_pass) -- first argument comes from: Prelude.drop 6 "_aapi_pass"
authSplice :: C.Splice (StateT AuthAPI IO)
authSplice = authSpliceH (lift get)
This is just a simplified example - we can safely assume that we take all fields of a data constructor (AuthAPI in the example above), and apply some kind of processing to come up with splice pattern ("user" and "pass" above - I have modeled it after Aeson deriveJSON). I could apply something like that to "Trans a" type where we have like 30 different data constructors (30 different transactions) for "a". Making splice building an automatic derivation would be a big help since all we need to do is to define the data constructor, and let the splice be derived automatically like in Aeson, instead of manually writing the code for each data constructor.
Has something like this been done before? If so, it will be very helpful to have example code. Meanwhile, I will keep reading Aeson source code to figure out how to do automatic derivation.
data AuthAPI = AuthAPI {
_aapi_user :: Text
,_aapi_pass :: Text
} deriving (Read, Show)
load :: MonadIO n => FilePath -> Splices (Splice n) -> IO (HeistState n)
load baseDir splices = do
tmap <- runEitherT $ do
let sc = mempty & scLoadTimeSplices .~ defaultLoadTimeSplices
& scCompiledSplices .~ splices
& scTemplateLocations .~ [loadTemplates baseDir]
initHeist $ emptyHeistConfig & hcNamespace .~ ""
& hcErrorNotBound .~ False
& hcSpliceConfig .~ sc
either (error . Prelude.concat) return tmap
`B.ByteString` is from `Data.ByteString` which `B` is alias for.
`StateT` is `Control.Monad.Trans.State.Strict.StateT`.
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Derive
import Data.Text (Text)
data AuthAPI = AuthAPI { _autha_uname :: String, _autha_pass :: Text} deriving (Show)
deriveHeistBuilder (Prelude.drop 7) ''AuthAPI
main = do
authBuilder <- genSpliceBuilder "." "auth"
req <- genReqH (authBuilder) (AuthAPI { _autha_uname = "JohnDoe", _autha_pass = "whatdoyouthink"})
print req
<API_root><authapi><login><user><uname/></user><password><pass/></password></login></authapi></API_root>
*Main> main
"<API_root><login><user>JohnDoe</user><password>whatdoyouthink</password></login></API_root>"