refactor: simplify control flow in App.postgrest

Currently, authentication and response execution each unwrap ExceptT with separate runExceptT calls, which split the main request flow across nested pattern matching and Either handling. Control flow is complex and difficult to understand.

The goal of this change is to make request execution as sequential
monadic code with clear error handling.

To implement that, request handling is now run in ExceptT over WriterT (Last ByteString) IO monad stack. Auth role is written after authentication succeeds and further returned along the response. Thanks to it response observation generation is centralized at the end of request handling.

It was necessary to abstract monad stack in getAuthResult, lookupJwtCache, postgrestResponse, and withTiming to enable introduction of WriterT.
This commit is contained in:
Michał Kłeczek
2026-06-02 11:28:19 +05:00
committed by Taimoor Zaeem
parent 1d6e0bd35f
commit 13c0e7061e
3 changed files with 32 additions and 37 deletions
+5 -9
View File
@@ -10,6 +10,7 @@ Authentication should always be implemented in an external service.
In the test suite there is an example of simple login function that can be used for a
very simple authentication system inside the PostgreSQL database.
-}
{-# LANGUAGE FlexibleContexts #-}
module PostgREST.Auth
( getAuthResult )
where
@@ -25,14 +26,9 @@ import Protolude
-- | Perform authentication and authorization
-- Parse JWT and return AuthResult
getAuthResult :: AppState -> Maybe ByteString -> IO (Either Error AuthResult)
getAuthResult :: (MonadError Error m, MonadIO m) => AppState -> Maybe ByteString -> m AuthResult
getAuthResult appState token = do
conf <- getConfig appState
time <- getTime appState
conf <- liftIO $ getConfig appState
time <- liftIO $ getTime appState
let jwtCacheState = getJwtCacheState appState
parseJwt = runExceptT $ do
claims <- lookupJwtCache jwtCacheState token
parseClaims conf time claims
parseJwt
parseClaims conf time =<< lookupJwtCache (getJwtCacheState appState) token