add argumentCombinator
This commit is contained in:
parent
d80994067d
commit
447a807cf0
2 changed files with 110 additions and 0 deletions
28
servant-server/src/Servant/Server/CombinatorUtils.hs
Normal file
28
servant-server/src/Servant/Server/CombinatorUtils.hs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
{-# LANGUAGE TypeOperators #-}
|
||||||
|
|
||||||
|
module Servant.Server.CombinatorUtils (
|
||||||
|
RouteResult(..),
|
||||||
|
argumentCombinator,
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.Proxy
|
||||||
|
import Network.Wai
|
||||||
|
|
||||||
|
import Servant.API
|
||||||
|
import Servant.Server
|
||||||
|
import Servant.Server.Internal
|
||||||
|
|
||||||
|
argumentCombinator ::
|
||||||
|
forall api combinator arg context env .
|
||||||
|
(ServerT (combinator :> api) Handler ~ (arg -> ServerT api Handler),
|
||||||
|
HasServer api context) =>
|
||||||
|
(Request -> RouteResult arg)
|
||||||
|
-> Proxy (combinator :> api)
|
||||||
|
-> Context context
|
||||||
|
-> Delayed env (Server (combinator :> api))
|
||||||
|
-> Router' env RoutingApplication
|
||||||
|
argumentCombinator getArg Proxy context delayed =
|
||||||
|
route (Proxy :: Proxy api) context $ addBodyCheck delayed $
|
||||||
|
DelayedIO $ \ request -> return $ getArg request
|
82
servant-server/test/Servant/Server/CombinatorUtilsSpec.hs
Normal file
82
servant-server/test/Servant/Server/CombinatorUtilsSpec.hs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
{-# LANGUAGE TypeOperators #-}
|
||||||
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
|
|
||||||
|
module Servant.Server.CombinatorUtilsSpec where
|
||||||
|
|
||||||
|
import Blaze.ByteString.Builder
|
||||||
|
import Control.Concurrent
|
||||||
|
import Data.ByteString.Lazy
|
||||||
|
import Data.Monoid
|
||||||
|
import Data.Proxy
|
||||||
|
import Data.String.Conversions
|
||||||
|
import Network.HTTP.Types
|
||||||
|
import Network.Wai
|
||||||
|
import Network.Wai.Internal
|
||||||
|
import Test.Hspec
|
||||||
|
|
||||||
|
import Servant.API
|
||||||
|
import Servant.Server
|
||||||
|
import Servant.Server.CombinatorUtils
|
||||||
|
|
||||||
|
runApp :: Application -> Request -> IO Response
|
||||||
|
runApp app req = do
|
||||||
|
mvar <- newMVar Nothing
|
||||||
|
app req $ \ response -> do
|
||||||
|
modifyMVar mvar $ \ Nothing ->
|
||||||
|
return $ (Just response, ResponseReceived)
|
||||||
|
modifyMVar mvar $ \mResponse -> do
|
||||||
|
case mResponse of
|
||||||
|
Nothing -> error "shouldn't happen"
|
||||||
|
Just response -> return (Just response, response)
|
||||||
|
|
||||||
|
responseBodyLbs :: Response -> IO ByteString
|
||||||
|
responseBodyLbs response = do
|
||||||
|
let (_, _, action) = responseToStream response
|
||||||
|
action $ \ streamingBody -> do
|
||||||
|
mvar <- newMVar ""
|
||||||
|
streamingBody
|
||||||
|
(\ builder -> modifyMVar_ mvar $ \ acc ->
|
||||||
|
return $ acc <> toLazyByteString builder)
|
||||||
|
(return ())
|
||||||
|
readMVar mvar
|
||||||
|
|
||||||
|
spec :: Spec
|
||||||
|
spec = do
|
||||||
|
it "allows to write a combinator by providing a function (Request -> a)" $ do
|
||||||
|
let server = return
|
||||||
|
app = serve (Proxy :: Proxy (Custom :> Get' String)) server
|
||||||
|
request = defaultRequest{
|
||||||
|
requestHeaders =
|
||||||
|
("Custom", "foo") :
|
||||||
|
requestHeaders defaultRequest
|
||||||
|
}
|
||||||
|
response <- runApp app request
|
||||||
|
responseBodyLbs response `shouldReturn` "\"foo\""
|
||||||
|
|
||||||
|
it "allows to write a combinator the errors out" $ do
|
||||||
|
let server = return
|
||||||
|
app = serve (Proxy :: Proxy (Custom :> Get' String)) server
|
||||||
|
request = defaultRequest
|
||||||
|
response <- runApp app request
|
||||||
|
responseStatus response `shouldBe` status400
|
||||||
|
|
||||||
|
it "allows to pick the phase of request consumption" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
type Get' = Get '[JSON]
|
||||||
|
|
||||||
|
data Custom
|
||||||
|
|
||||||
|
instance HasServer api context => HasServer (Custom :> api) context where
|
||||||
|
type ServerT (Custom :> api) m = String -> ServerT api m
|
||||||
|
route = argumentCombinator getCustom
|
||||||
|
|
||||||
|
getCustom :: Request -> RouteResult String
|
||||||
|
getCustom request = case lookup "Custom" (requestHeaders request) of
|
||||||
|
Nothing -> FailFatal err400
|
||||||
|
Just l -> Route $ cs l
|
Loading…
Reference in a new issue