2
votes

I'm trying to create client bindings to Web API using servant library. I want to be able to send any JSON objects.

import           Control.Monad.Trans.Except (ExceptT, runExceptT)
import           Data.Proxy
import           Network.HTTP.Client (Manager)
import           Servant.API
import           Servant.Client
import           Data.Aeson

-- | This methods accepts any instance of 'ToJSON'
--   I would like to have only this method exported from the module
send :: ToJSON a => a -> Manager -> IO (Either ServantError Result)
send x manager = runExceptT $ send_ x manager baseUrl

type MyAPI a = "acceptAnyJson" 
    :> ReqBody '[JSON] a
    :> Post '[JSON] Result

api :: ToJSON a => Proxy (MyAPI a) 
api = Proxy 

send_ :: ToJSON a => a -> Manager -> BaseUrl -> ExceptT ServantError IO Result
send_ = client api

Right now when I try to compile it I have error message:

Couldn't match type ‘a0’ with ‘a’
      because type variable ‘a’ would escape its scope
    This (rigid, skolem) type variable is bound by
      the inferred type for ‘send_’:
      ...

How can I parameterize my MyAPI, client and Proxy to accept type variable?

1

1 Answers

2
votes

You'll need to tie the type of api to the type of the thing you're sending:

{-# LANGUAGE ScopedTypeVariables #-}
send_ :: forall a. (FromJSON a) => a -> Manager -> BaseUrl -> ExceptT ServantError IO Result
send_ = client (api :: Proxy (MyAPI a))

or why even bother with api at that point:

send_ = client (Proxy :: Proxy (MyAPI a))