@@ -1,5 +1,7 @@
11{-# LANGUAGE DataKinds #-}
22{-# LANGUAGE TypeOperators #-}
3+{-# LANGUAGE GADTs #-}
4+{-# LANGUAGE ViewPatterns #-}
35
46module Servant.ClientSpec where
57
@@ -7,6 +9,7 @@ import Control.Concurrent
79import Control.Exception
810import Control.Monad.Trans.Either
911import Data.Proxy
12+import Data.Typeable
1013import Network.Socket
1114import Network.URI
1215import Network.Wai
@@ -23,6 +26,7 @@ type Api =
2326 "get" :> Get Person
2427 :<|> "capture" :> Capture "name" String :> Get Person
2528 :<|> "body" :> ReqBody Person :> Post Person
29+ :<|> "param" :> QueryParam "name" String :> Get Person
2630api :: Proxy Api
2731api = Proxy
2832
@@ -31,6 +35,10 @@ server = serve api (
3135 return alice
3236 :<|> (\ name -> return $ Person name 0)
3337 :<|> 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"))
3442 )
3543
3644withServer :: (URIAuth -> IO a) -> IO a
@@ -39,7 +47,8 @@ withServer action = withWaiDaemon (return server) (action . mkHost "localhost")
3947getGet :: URIAuth -> EitherT String IO Person
4048getCapture :: String -> URIAuth -> EitherT String IO Person
4149getBody :: Person -> URIAuth -> EitherT String IO Person
42−(getGet :<|> getCapture :<|> getBody) = client api
50+getQueryParam :: Maybe String -> URIAuth -> EitherT String IO Person
51+(getGet :<|> getCapture :<|> getBody :<|> getQueryParam) = client api
4352
4453spec :: Spec
4554spec = do
@@ -53,6 +62,34 @@ spec = do
5362 let p = Person "Clara" 42
5463 runEitherT (getBody p host) `shouldReturn` Right p
5564
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"
69+
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"
80+ mapM_ test $
81+ (WrappedApi (Proxy :: Proxy Delete)) :
82+ (WrappedApi (Proxy :: Proxy (Get ()))) :
83+ (WrappedApi (Proxy :: Proxy (Post ()))) :
84+ (WrappedApi (Proxy :: Proxy (Put ()))) :
85+ []
86+
87+data WrappedApi where
88+ WrappedApi :: (HasServer api, Server api ~ EitherT (Int, String) IO a,
89+ HasClient api, Client api ~ (URIAuth -> EitherT String IO ()),
90+ Typeable api) =>
91+ Proxy api -> WrappedApi
92+
5693
5794-- * utils
5895