Prefer ServantT for server to consume App context
Long story -> short: I'd like to access my App monad from within my Servant handlers. While this code type-checks, I'm not sure it's working as intended. Needing to change throwError to throwIO fails the "smell test". I expect to refactor this code, but I'm calling it a night for now.
This commit is contained in:
parent
bbcd0bf27d
commit
f61ed25755
2 changed files with 33 additions and 24 deletions
|
@ -6,41 +6,47 @@ import Servant
|
||||||
import API
|
import API
|
||||||
import Data.String.Conversions (cs)
|
import Data.String.Conversions (cs)
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
|
import Network.Wai.Middleware.Cors
|
||||||
import GoogleSignIn (EncodedJWT(..), ValidationResult(..))
|
import GoogleSignIn (EncodedJWT(..), ValidationResult(..))
|
||||||
import Utils
|
import Utils
|
||||||
|
|
||||||
import qualified Network.Wai.Handler.Warp as Warp
|
import qualified Network.Wai.Handler.Warp as Warp
|
||||||
import qualified Network.Wai.Middleware.Cors as Cors
|
|
||||||
import qualified GoogleSignIn
|
import qualified GoogleSignIn
|
||||||
import qualified Types as T
|
import qualified Types as T
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
server :: Server API
|
server :: ServerT API T.App
|
||||||
server = verifyGoogleSignIn
|
server = verifyGoogleSignIn
|
||||||
where
|
where
|
||||||
verifyGoogleSignIn :: T.VerifyGoogleSignInRequest -> Handler NoContent
|
verifyGoogleSignIn :: T.VerifyGoogleSignInRequest -> T.App NoContent
|
||||||
verifyGoogleSignIn T.VerifyGoogleSignInRequest{..} = do
|
verifyGoogleSignIn T.VerifyGoogleSignInRequest{..} = do
|
||||||
validationResult <- liftIO $ GoogleSignIn.validateJWT False (EncodedJWT idToken)
|
T.Context{..} <- ask
|
||||||
case validationResult of
|
validationResult <- liftIO $ GoogleSignIn.validateJWT False (EncodedJWT idToken)
|
||||||
Valid _ -> do
|
case validationResult of
|
||||||
-- If GoogleLinkedAccounts has email from JWT:
|
Valid _ -> do
|
||||||
-- create a new session for email
|
-- If GoogleLinkedAccounts has email from JWT:
|
||||||
-- Else:
|
-- create a new session for email
|
||||||
-- Redirect the SPA to the sign-up / payment page
|
-- Else:
|
||||||
pure NoContent
|
-- Redirect the SPA to the sign-up / payment page
|
||||||
err -> do
|
pure NoContent
|
||||||
throwError err401 { errBody = err |> GoogleSignIn.explainResult |> cs }
|
err -> do
|
||||||
|
-- TODO: I would prefer to use `throwError` here, but after changing
|
||||||
|
-- to ServerT, I couldn't get the code to compile.
|
||||||
|
throwIO err401 { errBody = err |> GoogleSignIn.explainResult |> cs }
|
||||||
|
|
||||||
run :: RIO T.Context ()
|
run :: T.App ()
|
||||||
run = do
|
run = do
|
||||||
T.Context{..} <- ask
|
ctx@T.Context{..} <- ask
|
||||||
liftIO $ Warp.run contextServerPort (enforceCors $ serve (Proxy @ API) $ server)
|
server
|
||||||
|
|> hoistServer (Proxy @ API) (runRIO ctx)
|
||||||
|
|> serve (Proxy @ API)
|
||||||
|
|> cors (const $ Just corsPolicy)
|
||||||
|
|> Warp.run contextServerPort
|
||||||
|
|> liftIO
|
||||||
where
|
where
|
||||||
enforceCors = Cors.cors (const $ Just corsPolicy)
|
corsPolicy :: CorsResourcePolicy
|
||||||
corsPolicy :: Cors.CorsResourcePolicy
|
corsPolicy = simpleCorsResourcePolicy
|
||||||
corsPolicy =
|
{ corsOrigins = Just (["http://localhost:8000"], True)
|
||||||
Cors.simpleCorsResourcePolicy
|
, corsMethods = simpleMethods ++ ["PUT", "PATCH", "DELETE", "OPTIONS"]
|
||||||
{ Cors.corsOrigins = Just (["http://localhost:8000"], True)
|
, corsRequestHeaders = simpleHeaders ++ ["Content-Type", "Authorization"]
|
||||||
, Cors.corsMethods = Cors.simpleMethods ++ ["PUT", "PATCH", "DELETE", "OPTIONS"]
|
}
|
||||||
, Cors.corsRequestHeaders = Cors.simpleHeaders ++ ["Content-Type", "Authorization"]
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ data Context = Context
|
||||||
, contextClientPort :: !Int
|
, contextClientPort :: !Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | Type synonym for my application monad.
|
||||||
|
type App = RIO Context
|
||||||
|
|
||||||
data VerifyGoogleSignInRequest = VerifyGoogleSignInRequest
|
data VerifyGoogleSignInRequest = VerifyGoogleSignInRequest
|
||||||
{ idToken :: !Text
|
{ idToken :: !Text
|
||||||
} deriving (Eq, Show)
|
} deriving (Eq, Show)
|
||||||
|
|
Loading…
Reference in a new issue