@@ -15,14 +15,13 @@ need to have some language extensions and imports:
16module Client where
16module Client where
18−import Control.Monad.Trans.Except
19import Data.Aeson
18import Data.Aeson
20import Data.Proxy
19import Data.Proxy
21import GHC.Generics
20import GHC.Generics
22−import Network.HTTP.Client (Manager, newManager, defaultManagerSettings)
21+import Network.HTTP.Client (newManager, defaultManagerSettings)
23import Servant.API
22import Servant.API
24import Servant.Client
23import Servant.Client
25−import System.IO.Unsafe
24+import Servant.Common.Req (ClientM, runClientM)
28Also, we need examples for some domain specific data types:
27Also, we need examples for some domain specific data types:
@@ -72,40 +71,28 @@ What we are going to get with **servant-client** here is 3 functions, one to que
72``` haskell
71``` haskell
73position :: Int -- ^ value for "x"
72position :: Int -- ^ value for "x"
74 -> Int -- ^ value for "y"
73 -> Int -- ^ value for "y"
75− -> ExceptT ServantError IO Position
74+ -> ClientM Position
77hello :: Maybe String -- ^ an optional value for "name"
76hello :: Maybe String -- ^ an optional value for "name"
78− -> ExceptT ServantError IO HelloMessage
77+ -> ClientM HelloMessage
80marketing :: ClientInfo -- ^ value for the request body
79marketing :: ClientInfo -- ^ value for the request body
81− -> ExceptT ServantError IO Email
80+ -> ClientM Email
84Each function makes available as an argument any value that the response may
83Each function makes available as an argument any value that the response may
85depend on, as evidenced in the API type. How do we get these functions? By calling
84depend on, as evidenced in the API type. How do we get these functions? By calling
86−the function `client`. It takes three arguments:
85+the function `client`. It takes one argument:
88- a `Proxy` to your API,
87- a `Proxy` to your API,
89−- a `BaseUrl`, consisting of the protocol, the host, the port and an optional subpath --
90− this basically tells `client` where the service that you want to query is hosted,
91−- a `Manager`, (from [http-client](http://hackage.haskell.org/package/http-client))
92−which manages http connections.
94``` haskell
89``` haskell
95api :: Proxy API
90api :: Proxy API
96api = Proxy
91api = Proxy
98−{-# NOINLINE __manager #-}
100−__manager = unsafePerformIO $ newManager defaultManagerSettings
102−position :<|> hello :<|> marketing =
93+position :<|> hello :<|> marketing = client api
103− client api (BaseUrl Http "localhost" 8081 "") __manager
106−(Yes, the usage of `unsafePerformIO` is very ugly, we know. Hopefully soon it'll
107−be possible to do without.)
109As you can see in the code above, we just "pattern match our way" to these functions. If we try to derive less or more functions than there are endpoints in the API, we obviously get an error. The `BaseUrl` value there is just:
96As you can see in the code above, we just "pattern match our way" to these functions. If we try to derive less or more functions than there are endpoints in the API, we obviously get an error. The `BaseUrl` value there is just:
111``` haskell ignore
98``` haskell ignore
@@ -127,7 +114,7 @@ data BaseUrl = BaseUrl
127That's it. Let's now write some code that uses our client functions.
114That's it. Let's now write some code that uses our client functions.
129``` haskell
116``` haskell
130−queries :: ExceptT ServantError IO (Position, HelloMessage, Email)
117+queries :: ClientM (Position, HelloMessage, Email)
131queries = do
118queries = do
132 pos <- position 10 10
119 pos <- position 10 10
133 message <- hello (Just "servant")
120 message <- hello (Just "servant")
@@ -136,7 +123,8 @@ queries = do
137run :: IO ()
124run :: IO ()
139− res <- runExceptT queries
126+ manager <- newManager defaultManagerSettings
127+ res <- runClientM queries (BaseUrl Http "localhost" 8081 "") manager
140 case res of
128 case res of
141 Left err -> putStrLn $ "Error: " ++ show err
129 Left err -> putStrLn $ "Error: " ++ show err
142 Right (pos, message, em) -> do
130 Right (pos, message, em) -> do