Haskell Servant client tutorial

1.2k views Asked by At

I am new to Haskell and Servant and am trying to get an official tutorial up and running. I have been trying to get this tutorial working to have a look at it and have been unable to get it working all day.I hate to post a question like this here but I honestly don't know why the code isn't working as I have made no changes to it. I am wondering has anyone else tried to implement this tutorial and has similar issues.

I have seen posts about some tutorials not working with with current servant versions anymore but this tutorial seems to be the most recent for Servant Client.

This is the tutorial http://haskell-servant.readthedocs.io/en/stable/tutorial/Client.html

Here is the code

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeOperators #-}

module Client where

import Data.Aeson
import Data.Proxy
import GHC.Generics
import Network.HTTP.Client (newManager, defaultManagerSettings)
import Servant.API
import Servant.Client

data Position = Position
  { x :: Int
  , y :: Int
  } deriving (Show, Generic)

instance FromJSON Position

newtype HelloMessage = HelloMessage { msg :: String }
  deriving (Show, Generic)

instance FromJSON HelloMessage

data ClientInfo = ClientInfo
  { clientName :: String
  , clientEmail :: String
  , clientAge :: Int
  , clientInterestedIn :: [String]
  } deriving Generic

instance ToJSON ClientInfo

data Email = Email
  { from :: String
  , to :: String
  , subject :: String
  , body :: String
  } deriving (Show, Generic)

instance FromJSON Email

type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
      :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
      :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email

position :: Int -> Int -> ClientM Position

hello :: Maybe String -> ClientM HelloMessage

marketing :: ClientInfo -> ClientM Email

api :: Proxy API
api = Proxy

position :<|> hello :<|> marketing = client api

queries :: ClientM (Position, HelloMessage, Email)
queries = do
  pos <- position 10 10 
  message <- hello (Just "servant") 
  em  <- marketing (ClientInfo "Alp" "[email protected]" 26 ["haskell", "mathematics"])
  return (pos, message, em)

run :: IO ()
run = do
  manager <- newManager defaultManagerSettings
  res <- runClientM queries (ClientEnv manager (BaseUrl Http "localhost" 8081 ""))
  case res of
    Left err -> putStrLn $ "Error: " ++ show err
    Right (pos, message, em) -> do
      print pos
      print message
      print em

Here are the errors I am getting

Couldn't match type ‘http-client-0.4.31.2:Network.HTTP.Client.Types.Manager
                           -> BaseUrl -> ClientM Position’
                     with ‘Control.Monad.Trans.Except.ExceptT ServantError IO Position’
      Expected type: Int -> Int -> ClientM Position
        Actual type: Int
                     -> Int
                     -> http-client-0.4.31.2:Network.HTTP.Client.Types.Manager
                     -> BaseUrl
                     -> ClientM Position
    • When checking that the inferred type
        position :: Int
                    -> Int
                    -> http-client-0.4.31.2:Network.HTTP.Client.Types.Manager
                    -> BaseUrl
                    -> ClientM Position
      is as general as its signature
        position :: Int -> Int -> ClientM Position


Variable not in scope:
      runClientM
        :: ClientM (Position, HelloMessage, Email)
           -> t0 -> IO (Either a0 (a1, a2, a3))


Data constructor not in scope:
      ClientEnv
        :: http-client-0.4.31.2:Network.HTTP.Client.Types.Manager
           -> BaseUrl -> t0
1

There are 1 answers

0
duplode On

The first "not in scope" error here mentions a ClientM type which, according to the servant-client changelog, was introduced by the 0.9 version of servant-client. Specifying servant-client >= 0.9 in the .cabal file dependencies will ensure cabal-install won't pull an older version (though note that, as of March 2020, 0.9 itself is quite old already). With cabal-install version 3, no further configuration steps should be necessary, as cabal build will automatically install any specified dependencies.