I’m working on a prototype of a microservice in purescript that uses my rabbitmq client wrapper written in js. Purescript code has to provide a handler that will be called when new event is received. The handler takes json object and a trace (string array) and should return a promise.
I wanted the subscribe function to take a -> Trace -> Aff Unit
hander function and wire it to the required Json -> Trace -> Effect (Promise Unit)
handler
It worked for a concrete type, but I have trouble changing it to a more generic implementation.
Here’s my code:
import Prelude
import Control.Promise (Promise, fromAff, toAffE)
import Effect (Effect)
import Effect.Class (liftEffect)
import Effect.Aff (Aff)
import Data.Either (Either, fromRight)
import Partial.Unsafe (unsafePartial)
import Data.Argonaut (Json)
import Data.Argonaut.Decode.Class (class DecodeJson, decodeJson)
import Data.Argonaut.Decode.Error (JsonDecodeError)
type Handler a
= forall a. DecodeJson a => a -> Trace -> Aff Unit
type PromiseHandler
= Json -> Trace -> Effect (Promise Unit)
newtype Trace
= Trace (Array String)
foreign import _bind :: MqContext -> String -> PromiseHandler -> Effect (Promise Unit)
subscribe :: forall a. DecodeJson a => MqContext -> String -> Handler a -> Aff Unit
subscribe ctx route handler = toAffE $ _bind ctx route (toPromiseHander handler)
toPromiseHander :: forall a. DecodeJson a => Handler a -> PromiseHandler
toPromiseHander handler event trace = fromAff $ handler decoded trace
where
decoded :: a
decoded = unsafePartial $ fromRight $ decodeJson event
Js part:
exports._bind = mq => route => handler => () => {
return mq.bind(route, (e, t) => handler(e)(t)())
}
Intended usage:
main :: Effect Unit
main =
launchAff_ do
Console.log "Starting"
let ctx = Mq.create "ps"
Mq.connect ctx
Mq.subscribe ctx "event.ps.test" (eventPsTest ctx)
Mq.ready ctx
eventPsTest :: MqContext -> Handler TestMsg
eventPsTest ctx event trace = do
Console.log $ "received: " <> show event <> " " <> show trace
Mq.publish ctx "event.ps.publish" "test" trace
pure unit
newtype TestMsg
= TestMsg { foo :: String }
derive newtype instance decodeJsonTestMsg :: DecodeJson TestMsg
derive newtype instance showTestMsg :: Show TestMsg
The error I get:
No type class instance was found for
Data.Argonaut.Decode.Class.DecodeJson t0
The instance head contains unknown type variables. Consider adding a type annotation.
while applying a function toPromiseHander
of type DecodeJson t0 => (forall a. DecodeJson a => a -> Trace -> ...) -> Json -> Trace -> Effect ...
to argument handler
while checking that expression toPromiseHander handler
has type Json -> Trace -> Effect (Promise Unit)
in value declaration subscribe
where t0 is an unknown type
What am I missing?
Thanks for any help