Search code examples
facebookhaskellhttp-redirectmonadsyesod

How to redirect within a monad in Yesod?


I'm currently using the fb package to write a Yesod app that takes data from Facebook. In my Handler, I've managed to get the first step of the authentication to work, but I need to redirect to the url that getUserAccessTokenStep1 returns, which I've defined as fbRedirUrl. I'm having trouble with all the monad wrapping and type checking to make sure I can redirect to this url.

getAccessTokenR :: Handler RepHtml
getAccessTokenR = do
  withManager $ \manager -> do
    FB.runFacebookT creds manager $ do
      fbRedirUrl <- FB.getUserAccessTokenStep1 redirUrl []
      liftIO $ print fbRedirUrl

Solution

  • It looks like if you pass the redirect URL back out through those layers of managers/Facebook monad then you can just feed it. The redirected URL's type is Text, which has an instance of RedirectUrl typeclass, necessary for using the redirect function (as seen in the documentation).

    You should be able to make this work with something like:

    getAccessTokenR :: Handler RepHtml
    getAccessTokenR = do
      url <- withManager $ \manager ->
        FB.runFacebookT creds manager $
           FB.getUserAccessTokenStep1 redirUrl []
      redirect url
    

    There's no real magic here, you basically have two high-level patterns going on, one is the "with" pattern, that will localize a resource's usage (in this case the manager) and the other is the "run" pattern, that is really the use of Monad transformers (don't worry too much about the details of that yet!).

    So withManager gives you a manager to use, presumably it takes care of some setup and takedown of the manager. This is probably typed something like

    withManager :: (Manager -> Handler a) -> Handler a
    

    Within that you have the facebook runner, which will be typed as:

    runFacebookT :: Credentials -> Manager -> FacebookT Auth Handler a -> Handler a
    

    Which basically says that if you give it some credentials, the manager, and some Facebook specific computation (like getting the redirect URL) it can translate that into your Monad of choice (here we pick Handler, because that's what withManager wants). In your case the a type variable is the Text of the redirect URL.

    Using this pair of with and run patterns, we get the result that the URL which was supplied in the deep down in there, bubbles up into our Handler monad. Then we just snag it out and give it to the redirect function!