Created
December 18, 2012 17:04
-
-
Save tcrayford/4329803 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Responder a where | |
respond :: a -> Controller () | |
class Injectable a where | |
inject :: Controller (Maybe a) | |
instance (Injectable a, Responder b) => Responder (a -> b) where | |
respond f = do | |
a <- inject | |
case a of | |
(Just arg) -> respond $ f arg | |
Nothing -> pass | |
-- then when wiring your handlers up into routes, you call `respond` on each handler | |
-- and each handler can take any arguments that are "injected" out of the web request | |
-- an example | |
newtype UserId = UserId Int deriving (Show, Eq) | |
newtype Email = Email Text deriving (Show, Eq) | |
data CurrentUser = CurrentUser UserId Email deriving (Show, Eq) | |
instance Injectable CurrentUser where | |
inject = do | |
userId <- getIdFromSession | |
record $ findByUserId userId | |
editPost :: CurrentUser -> Controller () | |
editPost u = undefined | |
-- record runs a custom monad, which is basically a `ReaderT` of the db connection, which is also contained inside my | |
-- `Controller` monad | |
-- `Controller` is just a ReaderT wrapper around the snap monad that lets me hide the fact that controller | |
-- actions need to pass the database connection to the db layer | |
-- This isn't perfect, because we can't respond in a custom way when the injection fails. | |
-- Ideally inject would have the following type signature: | |
-- class Injectable a where | |
-- inject :: (Responder b) => Controller (Either b a) | |
-- but I couldn't make the compiler happy with that yet. Might need multiparam typeclasses or summat :( |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment