rest-example - example of handling nested ReaderT
ronslow opened this issue · 2 comments
ronslow commented
I am following rest-examples, simplifying, and building a service to return a single Booking, identified by BookingId, from an (AcidState Diary)
newtype DiaryApi a = DiaryApi { unDiaryApi :: ReaderT (AcidState Diary) IO a }
deriving ( Applicative
, Functor
, Monad
, MonadIO
, MonadReader (AcidState Diary)
)
type WithBookingId = ReaderT BookingId DiaryApi
resource :: Resource DiaryApi WithBookingId BookingId Void Void
resource = mkResourceReader { R.name = "booking"
, R.get = Just getBooking
}
getBooking :: Handler WithBookingId
getBooking = mkIdHandler jsonO handler where
handler :: () -> BookingId -> ExceptT (Reason Void) WithBookingId Booking
handler _ bid = do
diary <- lift $ DiaryApi $ lift $ ask -- this is the problem line
return $ liftIO $ query diary (GetBooking bid) -- this line is looking up the booking in the AcidState Diary, works within IO, and is known to be correct
The problem line of course lifts the diary into a ExceptT (Reason Void) BookingApi Booking monad, whereas I need it to be inside an ExceptT (Reason Void) WithBookingId Booking monad
Am I going about this in the right way? Is it correct to nest ReaderT in this way for subresources?
Robert
ronslow commented
getBooking = mkIdHandler jsonO handler where
handler :: () -> BookingId -> ExceptT (Reason Void) WithBookingId (Maybe Booking)
handler _ bid = lift handler'
handler' :: WithBookingId (Maybe Booking)
handler' = do
bid <- ask
lift $ handler'' bid
handler'' :: BookingId -> DiaryApi (Maybe Booking)
handler'' bid = do
diary <- DiaryApi ask
liftIO $ query diary (AS.GetBooking bid)
The moral of the story was of course to subdivide the problem into typechecked definitions and then use the typechecker to guide to the solution
hesselink commented
Sorry for not responding sooner to this, good to see you found the solution (lift ask
).