Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

About writing explicit types for the client functions #105

Open
ibizaman opened this issue Jan 1, 2021 · 2 comments
Open

About writing explicit types for the client functions #105

ibizaman opened this issue Jan 1, 2021 · 2 comments

Comments

@ibizaman
Copy link

ibizaman commented Jan 1, 2021

This is not an issue but a way of documenting my findings.

Having the following API:

import Servant.API ((:<|>), (:>))
import qualified Servant.API as S

type API =
  "list" :> S.Get '[S.JSON] [Entity User]
    :<|> "add" :> S.ReqBody '[S.JSON] User :> S.Post '[S.JSON] UserId
    :<|> "remove" :> S.ReqBody '[S.JSON] UserId :> S.Post '[S.JSON] Bool

I can get the following functions from servant-reflex:

import qualified Reflex.Dom as Dom
import qualified Servant.Reflex as SR
import Servant.API ((:<|>) (..))

srList :<|> srAdd :<|> srRemove =
  SR.client
    (Proxy :: Proxy API)
    (Proxy :: Proxy (m :: * -> *))
    (Proxy :: Proxy ())
    (Dom.constDyn (SR.BasePath "http://localhost:8080"))

For this to work, I needed to disable the monomorphism restriction with:

{-# LANGUAGE NoMonomorphismRestriction #-}

Also, I like to write explicit type signatures so I came up with the following:

import qualified Language.Javascript.JSaddle as JSaddle

srList ::
  SR.SupportsServantReflex t m =>
  Dom.Event t () ->
  m (Dom.Event t (SR.ReqResult () [Entity User]))
srAdd ::
  SR.SupportsServantReflex t m =>
  Dom.Dynamic t (Either Text User) ->
  Dom.Event t () ->
  m (Dom.Event t (SR.ReqResult () UserId))
srRemove ::
  SR.SupportsServantReflex t m =>
  Dom.Dynamic t (Either Text UserId) ->
  Dom.Event t () ->
  m (Dom.Event t (SR.ReqResult () Bool))

I do not use Dom.MonadWidget because that issues a warning from the simplifiable-class-constraints flag:

app/main.hs:38:3: warning: [-Wsimplifiable-class-constraints]
    • The constraint ‘Dom.MonadWidget t m’
        matches an instance declaration
      instance Reflex.Dom.Old.MonadWidgetConstraints t m =>
               Dom.MonadWidget t m
        -- Defined in ‘Reflex.Dom.Old’
      This makes type inference for inner bindings fragile;
        either use MonoLocalBinds, or simplify it using the instance
    • In the type signature:
        srList :: Dom.MonadWidget t m =>
                  Dom.Event t () -> m (Dom.Event t (SR.ReqResult () [Entity User]))
@imalsogreg
Copy link
Owner

This is great! I'll try to incorporate it into the readme.

@danwdart
Copy link

danwdart commented Oct 9, 2021

I also had an issue with * being conflated with * -> * in 0.3.5. I used your m :: (* -> *) trick with NoMonomorphismRestriction (and KindSignatures of course), but I also got:

Non type-variable argument
        in the constraint: HasJSContext (Performable m1)
      (Use FlexibleContexts to permit this)

so I also enabled FlexibleContexts.
I do use MonadWidget but that requires me also to enable MonoLocalBinds.
After that, it works and I no longer have to define a service and XHR stuff! Huzzah!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants