hoodunit / purescript-payload

An HTTP server and client library for PureScript
Apache License 2.0
100 stars 11 forks source link

Support monad transformer stacks #7

Open eviefp opened 4 years ago

eviefp commented 4 years ago

While looking into payload, I was trying to write some simple example of an API and rather than use a real DB, I figured I'd use a StateT transformer to keep some state across API calls, but I noticed the exposed functions force handlers to run in Aff.

I assume it should be possible to relax the requirement to MonadAff?

hoodunit commented 4 years ago

I've been vaguely thinking about introducing something like Servant's natural transformation API to allow use cases like this. This should be possible.

roryc89 commented 3 years ago

In our project, we handle this outside of the payload library, by mapping over the handlers record and running our own monad.


  handlers env = 
    runHandlers env 
      { avatarDelete: avatarDelete :: _ -> ServerM _
      , avatarSignedUrl: avatarSignedUrl :: _ -> ServerM _
      , changeEmail: changeEmail :: _ -> ServerM _
      , hasuraAuthenticate: hasuraAuthenticate :: _ -> ServerM _
      , hasuraAuthenticateAdmin: hasuraAuthenticateAdmin :: _ -> ServerM _
      , hasuraAuthenticateNotVerified: hasuraAuthenticateNotVerified :: _ -> ServerM _
      , signIn: signIn :: _ -> ServerM _
      , signInGoogle: signInGoogle :: _ -> ServerM _
      , signInLinkedin: signInLinkedin :: _ -> ServerM _
      , register: register :: _ -> ServerM _
      , checkUser: checkUser :: _ -> ServerM _
      , renderPdf: renderPdf :: _ -> ServerM _
      , resetPassword: resetPassword :: _ -> ServerM _
      , sendPasswordResetEmail: sendPasswordResetEmail :: _ -> ServerM _
      , sendVerificationEmail: sendVerificationEmail :: _ -> ServerM _
      , verifyEmail: verifyEmail :: _ -> ServerM _
      , hasuraPublic: hasuraPublic :: _ -> ServerM _
      }
...
import Prelude

import Data.Maybe (Maybe(..))
import Data.Symbol (class IsSymbol, SProxy, reflectSymbol)
import Effect.Aff (Aff)
import Env (Env(..))
import Heterogeneous.Mapping (class HMapWithIndex, class MappingWithIndex, hmapWithIndex)
import ServerM (ServerM, runServerM)

data RunHandler
  = RunHandler Env

instance runHandler ::
  ( IsSymbol sym
    ) =>
  MappingWithIndex RunHandler (SProxy sym) (r -> ServerM res) (r -> Aff res) where
  mappingWithIndex (RunHandler (Env env)) sym h req =
    runServerM
      ( Env
          env
            { path = Just $ reflectSymbol sym }
      )
      (h req)

runHandlers ::
  forall serverMs affs.
  HMapWithIndex RunHandler serverMs affs => Env -> serverMs -> affs
runHandlers = hmapWithIndex <<< RunHandler