@@ -1,5 +1,7 @@
1{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE TypeOperators #-}
2{-# LANGUAGE TypeOperators #-}
4+{-# LANGUAGE ViewPatterns #-}
4module Servant.ClientSpec where
6module Servant.ClientSpec where
@@ -7,6 +9,7 @@ import Control.Concurrent
7import Control.Exception
9import Control.Exception
8import Control.Monad.Trans.Either
10import Control.Monad.Trans.Either
9import Data.Proxy
11import Data.Proxy
10import Network.Socket
13import Network.Socket
11import Network.URI
14import Network.URI
12import Network.Wai
15import Network.Wai
@@ -23,6 +26,7 @@ type Api =
23 "get" :> Get Person
26 "get" :> Get Person
24 :<|> "capture" :> Capture "name" String :> Get Person
27 :<|> "capture" :> Capture "name" String :> Get Person
25 :<|> "body" :> ReqBody Person :> Post Person
28 :<|> "body" :> ReqBody Person :> Post Person
29+ :<|> "param" :> QueryParam "name" String :> Get Person
26api :: Proxy Api
30api :: Proxy Api
27api = Proxy
31api = Proxy
@@ -31,6 +35,10 @@ server = serve api (
31 return alice
35 return alice
32 :<|> (\ name -> return $ Person name 0)
36 :<|> (\ name -> return $ Person name 0)
33 :<|> return
37 :<|> return
38+ :<|> (\ name -> case name of
39+ Just "alice" -> return alice
40+ Just name -> left (400, name ++ " not found")
41+ Nothing -> left (400, "missing parameter"))
36withServer :: (URIAuth -> IO a) -> IO a
44withServer :: (URIAuth -> IO a) -> IO a
@@ -39,7 +47,8 @@ withServer action = withWaiDaemon (return server) (action . mkHost "localhost")
39getGet :: URIAuth -> EitherT String IO Person
47getGet :: URIAuth -> EitherT String IO Person
40getCapture :: String -> URIAuth -> EitherT String IO Person
48getCapture :: String -> URIAuth -> EitherT String IO Person
41getBody :: Person -> URIAuth -> EitherT String IO Person
49getBody :: Person -> URIAuth -> EitherT String IO Person
50+getQueryParam :: Maybe String -> URIAuth -> EitherT String IO Person
42−(getGet :<|> getCapture :<|> getBody) = client api
51+(getGet :<|> getCapture :<|> getBody :<|> getQueryParam) = client api
44spec :: Spec
53spec :: Spec
@@ -53,6 +62,34 @@ spec = do
53 let p = Person "Clara" 42
62 let p = Person "Clara" 42
54 runEitherT (getBody p host) `shouldReturn` Right p
63 runEitherT (getBody p host) `shouldReturn` Right p
65+ it "Servant.API.QueryParam" $ withServer $ \ host -> do
66+ runEitherT (getQueryParam (Just "alice") host) `shouldReturn` Right alice
67+ Left result <- runEitherT (getQueryParam (Just "bob") host)
68+ result `shouldContain` "bob not found"
70+ context "client correctly handles error status codes" $ do
71+ let test :: WrappedApi -> Spec
72+ test (WrappedApi api) =
73+ it (show (typeOf api)) $
74+ withWaiDaemon (return (serve api (left (500, "error message")))) $
75+ \ (mkHost "localhost" -> host) -> do
76+ let getResponse :: URIAuth -> EitherT String IO ()
77+ getResponse = client api
78+ Left result <- runEitherT (getResponse host)
79+ result `shouldContain` "error message"
81+ (WrappedApi (Proxy :: Proxy Delete)) :
82+ (WrappedApi (Proxy :: Proxy (Get ()))) :
83+ (WrappedApi (Proxy :: Proxy (Post ()))) :
84+ (WrappedApi (Proxy :: Proxy (Put ()))) :
88+ WrappedApi :: (HasServer api, Server api ~ EitherT (Int, String) IO a,
89+ HasClient api, Client api ~ (URIAuth -> EitherT String IO ()),
91+ Proxy api -> WrappedApi