on master help sign in
Merge pull request #17 from haskell-servant/raw-fullresponse
989849cAlp Mestanogullari
servant-client.cabal+1
@@ -74,6 +74,7 @@ test-suite spec
74 , http-client
74 , http-client
75 , http-media
75 , http-media
76 , http-types
76 , http-types
77+ , HUnit
77 , network >= 2.6
78 , network >= 2.6
78 , QuickCheck >= 2.7
79 , QuickCheck >= 2.7
79 , servant >= 0.2.1
80 , servant >= 0.2.1
src/Servant/Client.hs+4−3
@@ -23,6 +23,7 @@ import Data.Proxy
23import Data.String.Conversions
23import Data.String.Conversions
24import Data.Text (unpack)
24import Data.Text (unpack)
25import GHC.TypeLits
25import GHC.TypeLits
26+import Network.HTTP.Client (Response)
26import Network.HTTP.Media
27import Network.HTTP.Media
27import qualified Network.HTTP.Types as H
28import qualified Network.HTTP.Types as H
28import Servant.API
29import Servant.API
@@ -411,12 +412,12 @@ instance (KnownSymbol sym, HasClient sublayout)
411 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
412 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
412
413
413-- | Pick a 'Method' and specify where the server you want to query is. You get
414-- | Pick a 'Method' and specify where the server you want to query is. You get
414−-- back the status code and the response body as a 'ByteString'.
415+-- back the full `Response`.
415instance HasClient Raw where
416instance HasClient Raw where
416− type Client Raw = H.Method -> BaseUrl -> EitherT ServantError IO (Int, ByteString, MediaType)
417+ type Client Raw = H.Method -> BaseUrl -> EitherT ServantError IO (Int, ByteString, MediaType, Response ByteString)
417
418
418 clientWithRoute :: Proxy Raw -> Req -> Client Raw
419 clientWithRoute :: Proxy Raw -> Req -> Client Raw
419− clientWithRoute Proxy req httpMethod host =
420+ clientWithRoute Proxy req httpMethod host = do
420 performRequest httpMethod req (const True) host
421 performRequest httpMethod req (const True) host
421
422
422-- | If you use a 'ReqBody' in one of your endpoints in your API,
423-- | If you use a 'ReqBody' in one of your endpoints in your API,
src/Servant/Common/Req.hs+3−3
@@ -133,7 +133,7 @@ displayHttpRequest :: Method -> String
133displayHttpRequest httpmethod = "HTTP " ++ cs httpmethod ++ " request"
133displayHttpRequest httpmethod = "HTTP " ++ cs httpmethod ++ " request"
134
134
135
135
136−performRequest :: Method -> Req -> (Int -> Bool) -> BaseUrl -> EitherT ServantError IO (Int, ByteString, MediaType)
136+performRequest :: Method -> Req -> (Int -> Bool) -> BaseUrl -> EitherT ServantError IO (Int, ByteString, MediaType, Response ByteString)
137performRequest reqMethod req isWantedStatus reqHost = do
137performRequest reqMethod req isWantedStatus reqHost = do
138 partialRequest <- liftIO $ reqToRequest req reqHost
138 partialRequest <- liftIO $ reqToRequest req reqHost
139
139
@@ -159,13 +159,13 @@ performRequest reqMethod req isWantedStatus reqHost = do
159 Just t' -> pure t'
159 Just t' -> pure t'
160 unless (isWantedStatus status_code) $
160 unless (isWantedStatus status_code) $
161 left $ FailureResponse status ct body
161 left $ FailureResponse status ct body
162− return (status_code, body, ct)
162+ return (status_code, body, ct, response)
163
163
164performRequestCT :: MimeUnrender ct result =>
164performRequestCT :: MimeUnrender ct result =>
165 Proxy ct -> Method -> Req -> [Int] -> BaseUrl -> EitherT ServantError IO result
165 Proxy ct -> Method -> Req -> [Int] -> BaseUrl -> EitherT ServantError IO result
166performRequestCT ct reqMethod req wantedStatus reqHost = do
166performRequestCT ct reqMethod req wantedStatus reqHost = do
167 let acceptCT = contentType ct
167 let acceptCT = contentType ct
168− (_status, respBody, respCT) <-
168+ (_status, respBody, respCT, _response) <-
169 performRequest reqMethod (req { reqAccept = [acceptCT] }) (`elem` wantedStatus) reqHost
169 performRequest reqMethod (req { reqAccept = [acceptCT] }) (`elem` wantedStatus) reqHost
170 unless (matches respCT (acceptCT)) $
170 unless (matches respCT (acceptCT)) $
171 left $ UnsupportedContentType respCT respBody
171 left $ UnsupportedContentType respCT respBody
test/Servant/ClientSpec.hs+21−10
@@ -23,14 +23,15 @@ import Data.Monoid
23import Data.Proxy
23import Data.Proxy
24import qualified Data.Text as T
24import qualified Data.Text as T
25import GHC.Generics
25import GHC.Generics
26−import Network.HTTP.Client (HttpException(..))
26+import qualified Network.HTTP.Client as C
27import Network.HTTP.Media
27import Network.HTTP.Media
28import Network.HTTP.Types
28import Network.HTTP.Types
29import Network.Socket
29import Network.Socket
30−import Network.Wai
30+import Network.Wai hiding (Response)
31import Network.Wai.Handler.Warp
31import Network.Wai.Handler.Warp
32import Test.Hspec
32import Test.Hspec
33import Test.Hspec.QuickCheck
33import Test.Hspec.QuickCheck
34+import Test.HUnit
34import Test.QuickCheck
35import Test.QuickCheck
35
36
36import Servant.API
37import Servant.API
@@ -64,7 +65,7 @@ instance FromFormUrlEncoded Person where
64
65
65deriving instance Eq ServantError
66deriving instance Eq ServantError
66
67
67−instance Eq HttpException where
68+instance Eq C.HttpException where
68 a == b = show a == show b
69 a == b = show a == show b
69
70
70alice :: Person
71alice :: Person
@@ -128,8 +129,8 @@ getQueryFlag :: Bool -> BaseUrl -> EitherT ServantError IO Bool
128getMatrixParam :: Maybe String -> BaseUrl -> EitherT ServantError IO Person
129getMatrixParam :: Maybe String -> BaseUrl -> EitherT ServantError IO Person
129getMatrixParams :: [String] -> BaseUrl -> EitherT ServantError IO [Person]
130getMatrixParams :: [String] -> BaseUrl -> EitherT ServantError IO [Person]
130getMatrixFlag :: Bool -> BaseUrl -> EitherT ServantError IO Bool
131getMatrixFlag :: Bool -> BaseUrl -> EitherT ServantError IO Bool
131−getRawSuccess :: Method -> BaseUrl -> EitherT ServantError IO (Int, ByteString, MediaType)
132+getRawSuccess :: Method -> BaseUrl -> EitherT ServantError IO (Int, ByteString, MediaType, C.Response ByteString)
132−getRawFailure :: Method -> BaseUrl -> EitherT ServantError IO (Int, ByteString, MediaType)
133+getRawFailure :: Method -> BaseUrl -> EitherT ServantError IO (Int, ByteString, MediaType, C.Response ByteString)
133getMultiple :: String -> Maybe Int -> Bool -> [(String, [Rational])]
134getMultiple :: String -> Maybe Int -> Bool -> [(String, [Rational])]
134 -> BaseUrl
135 -> BaseUrl
135 -> EitherT ServantError IO (String, Maybe Int, Bool, [(String, [Rational])])
136 -> EitherT ServantError IO (String, Maybe Int, Bool, [(String, [Rational])])
@@ -211,12 +212,22 @@ spec = do
211 Arrow.left show <$> runEitherT (getMatrixFlag flag host) `shouldReturn` Right flag
212 Arrow.left show <$> runEitherT (getMatrixFlag flag host) `shouldReturn` Right flag
212
213
213 it "Servant.API.Raw on success" $ withServer $ \ host -> do
214 it "Servant.API.Raw on success" $ withServer $ \ host -> do
214− (Arrow.left show <$> runEitherT (getRawSuccess methodGet host))
215+ res <- runEitherT (getRawSuccess methodGet host)
216+ case res of
217+ Left e -> assertFailure $ show e
218+ Right (code, body, ct, response) -> do
215− `shouldReturn` Right (200, "rawSuccess", "application"//"octet-stream")
219+ (code, body, ct) `shouldBe` (200, "rawSuccess", "application"//"octet-stream")
220+ C.responseBody response `shouldBe` body
221+ C.responseStatus response `shouldBe` ok200
216
222
217 it "Servant.API.Raw on failure" $ withServer $ \ host -> do
223 it "Servant.API.Raw on failure" $ withServer $ \ host -> do
218− (Arrow.left show <$> runEitherT (getRawFailure methodGet host))
224+ res <- runEitherT (getRawFailure methodGet host)
225+ case res of
226+ Left e -> assertFailure $ show e
227+ Right (code, body, ct, response) -> do
219− `shouldReturn` Right (400, "rawFailure", "application"//"octet-stream")
228+ (code, body, ct) `shouldBe` (400, "rawFailure", "application"//"octet-stream")
229+ C.responseBody response `shouldBe` body
230+ C.responseStatus response `shouldBe` badRequest400
220
231
221 modifyMaxSuccess (const 20) $ do
232 modifyMaxSuccess (const 20) $ do
222 it "works for a combination of Capture, QueryParam, QueryFlag and ReqBody" $
233 it "works for a combination of Capture, QueryParam, QueryFlag and ReqBody" $
@@ -262,7 +273,7 @@ spec = do
262 Right host <- return $ parseBaseUrl "127.0.0.1:987654"
273 Right host <- return $ parseBaseUrl "127.0.0.1:987654"
263 Left res <- runEitherT (getGet host)
274 Left res <- runEitherT (getGet host)
264 case res of
275 case res of
265− ConnectionError (FailedConnectionException2 "127.0.0.1" 987654 False _) -> return ()
276+ ConnectionError (C.FailedConnectionException2 "127.0.0.1" 987654 False _) -> return ()
266 _ -> fail $ "expected ConnectionError, but got " <> show res
277 _ -> fail $ "expected ConnectionError, but got " <> show res
267
278
268 it "reports UnsupportedContentType" $ withFailServer $ \ host -> do
279 it "reports UnsupportedContentType" $ withFailServer $ \ host -> do