Change the server in interpreter?
stevemao opened this issue · 3 comments
Hi there, thanks for the write up.
I'm wondering if we want to change the server to serverless, is it easy to do that? If we treat the server is an effect, can we just change the interpreter?
Hi Steve,
That's a cool idea!
There is https://hackage.haskell.org/package/servant-polysemy which allows to run Servant as a polysemy effect. here is a very simple example:
https://github.com/AJChapman/servant-polysemy/blob/master/example/Server.hs
At the moment I don't have the time to do it. But all Pull requests are welcome!
Hi again Steve,
I came up with the following solution:
-
Define a new ExternalInterfaces.AppServer effect
-
Provide a Warp based implementation ExternalInterfaces.WarpAppServer
-
write a main function that runs the whole Polysemy application
here is the code: -
AppServer.hs:
{-# LANGUAGE TemplateHaskell #-}
module ExternalInterfaces.AppServer where
import Polysemy ( makeSem )
import Network.Wai (Application)
import InterfaceAdapters.Config
data AppServer m a where
ServeApp :: Int -> Application -> AppServer m ()
ServeAppFromConfig :: Config -> AppServer m ()
makeSem ''AppServer
- WarpAppServer.hs:
module ExternalInterfaces.WarpAppServer where
import ExternalInterfaces.AppServer
import Polysemy (Embed, Sem, Member, embed, interpret, runM )
import qualified Network.Wai.Handler.Warp as Warp (run)
import InterfaceAdapters.Config (Config(..))
import ExternalInterfaces.ApplicationAssembly (createApp, loadConfig)
-- | Warp Based implementation of AppServer
runWarpAppServer :: (Member (Embed IO) r) => Sem (AppServer : r) a -> Sem r a
runWarpAppServer = interpret $ \case
ServeApp port app -> embed $ Warp.run port app
ServeAppFromConfig config -> embed $
let p = port config
app = createApp config
in Warp.run p app
- Main.hs:
-- | in this example the AppServer effect is interpreted by runAppServerOnWarp
warpAsEffectMain :: IO ()
warpAsEffectMain = do
config <- loadConfig
serveAppFromConfig config
& runWarpAppServer -- use Warp to run rest application
& runM
What I like about this approach is that the polysemy effect interpretation now remains the outermost layer of the application.
Everything else, including the Warp server is now just an effect.
That makes the whole architecture still a bit cleaner!
Does this approach match your idea?
I put together a blog post that describes my solution:
https://thma.github.io/posts/2022-07-04-polysemy-and-warp.html