Search code examples
haskellscotty

How to use Scotty's ActionT monad like a Maybe monad, with an early http response returned for errors?


I would like to be able to return custom error pages and statuses to the user, and end computation in the ActionT monad when such an error occurs. My understanding is that this is a bit like a Maybe monad, where computation ends when the first Nothing is encountered, but with a final error message emitted (to the user via HTTP).

I have a code snippet that looks like this:

  liftIO $ scotty (config & port & fromEnum) $
    get "/cow/:mark" $ do
      qParams :: DM.Map LTxt.Text LTxt.Text <- DM.fromList <$> params
      markTxt <- param "mark"
      let intervalTxtMay = DM.lookup "interval" qParams
      let cowMarkMaybe = TR.readMaybe $ Txt.unpack markTxt
      cowMark <- case cowMarkMaybe of
        Nothing -> do
          status status404
          textLazy $ "Couldn't parse cow mark " ++  markTxt ++ " as integer."
          finish
        Just cmVal-> pure $ CowMark cmVal
      liftIO $ logLogIt Debug lgr ["***** Made it past cowMark ******"]
      ...

There are at least two problems with the code: finish doesn't seem to do anything particularly useful here, i.e., computation continues and I still see the message ***** Made it past cowMark ****** in my logs each time load a page that would normally trigger the 404. The second problem is that the 404 error is not enacted, I get a 200 response even when it should be a 404.

Is there a way to achieve the desired behavior in Scotty?


Solution

  • Both problems stem from the Nothing case never being entered, because the TR.readMaybe always succeeds. Print markTxt and cowMarkMaybe in a case where the latter should be Nothing.