Environment Monad with automatic resource refreshment

Latest on Hackage:

This package is not currently in any snapshots. If you're interested in using it, we recommend adding it to Stackage Nightly. Doing so will make builds more reliable, and allow to host generated Haddocks.

BSD3 licensed by Hiromi ISHII
Maintained by konn.jinro _at_

RefreshT -- Environment Monad with automatic resource refreshment


refresht package provides similar interface as ReaderT-monad, but it comes with automatic refreshment mechanism. In other words, the RefreshT monad transformer provides the general way to maintain the freshness of the external environment, with respoec to the specified condition or exceptions.

The typical usage is to communicate with the server which requires periodic refreshment of access tokens, such as Google API.


The following pseudo-code illustrates the typical usage:

import Control.Monad.Refresh

import Network.Wreq               (getWith, defaults)
import Control.Lens               ((&), (.~), (^.))
import Data.Time                  (addUTCTime, getCurrentTime, UTCTime)
import Data.ByetString.Lazy.Char8 (unpack)
import Control.Exception          (fromException)

data User = User { expiration  :: UTCTime
                 , accessToken :: String

main :: IO ()
main = do
  time <- getCurrentTime
  evalRefreshT conf (User (3600 `addUTCTime` time) "initialtoken") $ do
    rsc <- withEnv $ \User{..} ->
      getWith (defaults & auth .~ oauth2Bearer accessToken)
    putStrLn $ print rsc

conf :: RefreshSetting User IO
conf = defaultRefreshSetting
     & refresher         .~ update
     & shouldRefresh     .~ checkExpr
     & isRefreshingError .~ isRefreshing
    shouldRefresh usr = do -- checks expiration
      now <- getCurrentTime
      return $ now <= expiration usr
    update usr = do
      -- Refreshed token for the service
      bdy <- getWith
        (defaults & param "token" .~ [accessToken usr])
      let token = unpack $ bdy ^. responseBody
          usr'  = usr { accessToken = token
                      , expiration = ...

      -- Save updates in local file, or db.
      writeFile "database" (show usr')
      return usr'

    -- 401 Unauthorized exception should cause refreshment
    isRefreshing e =
      case fromException e of
        Just Error401 -> True
        _ -> False
Depends on 6 packages:
Used by 2 packages:
comments powered byDisqus