Skip to content

Instantly share code, notes, and snippets.

@eckyputrady
Last active April 2, 2023 12:07
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save eckyputrady/4cfa4eb0eb8370cb50c7ffaa92d33e2c to your computer and use it in GitHub Desktop.
Save eckyputrady/4cfa4eb0eb8370cb50c7ffaa92d33e2c to your computer and use it in GitHub Desktop.
Haskell Clean Architecture
-----------------------------
-- Domain.hs
type SessionId = Text
type UserId = Text
type User = Text
class (Monad m) => UserRepo m where
getUserById :: UserId -> m User
class (Monad m) => SessionRepo m where
getUserIdBySession :: SessionId -> m UserId
getUser :: (UserRepo m, SessionRepo m)
=> SessionId -> m User
getUser sId = getUserIdBySession sId
>>= getUserById
-----------------------------
-- Routes.hs
import qualified Domain
routes :: (Domain.UserRepo m, Domain.SessionRepo m) => m ()
routes =
get "/user" $ do
sId <- parseSessionFromCookiesSomehow
user <- Domain.getUser sId
displayUserSomeHow user
-----------------------------
-- Redis.hs
import qualified Domain
acquireConnection :: IO Connection
acquireConnection = ...
getUserById :: (Reader Connection m)
=> Domain.UserId -> m Domain.User
getUserById = ...
getUserIdBySession :: (Reader Connection m)
=> Domain.Session -> m Domain.UserId
getUserIdBySession = ...
-----------------------------
-- Main.hs
import qualified Domain
import qualified Redis
import qualified Routes
newtype App a = App
{ unApp :: ReaderT Connection IO a
} deriving ( Applicative, Functor, Monad
, MonadReader Connection, MonadIO
)
instance Domain.UserRepo App where
getUserById = Redis.getUserById
instance Domain.SessionRepo App where
getUserIdBySession = Redis.getUserIdBySession
main = do
conn <- Redis.acquireConnection
flip runReaderT conn . unApp $ Routes.routes
@aronluigi
Copy link

aronluigi commented Feb 16, 2018

Nice example! It will be really nice if you can make the code compile.

@Woody88
Copy link

Woody88 commented Mar 11, 2019

Great example. Just like the @aronluigi said, it would be nice if you could expand on it!

@reouno
Copy link

reouno commented Sep 16, 2019

Very nice example. Just like the @Woody88 said, it would be nice if you can make runnable code sample.

@arnemileswinter
Copy link

Wonderful example! Just like @reouno said, a compiling instance would be nice.

@eckyputrady
Copy link
Author

@arnemileswinter You might be interested in https://github.com/eckyputrady/haskell-scotty-realworld-example-app that uses the similar structure as this gist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment