add captureCombinator
This commit is contained in:
parent
447a807cf0
commit
16cffc7d69
3 changed files with 65 additions and 11 deletions
|
@ -45,6 +45,7 @@ library
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
Servant
|
Servant
|
||||||
Servant.Server
|
Servant.Server
|
||||||
|
Servant.Server.CombinatorUtils
|
||||||
Servant.Server.Experimental.Auth
|
Servant.Server.Experimental.Auth
|
||||||
Servant.Server.Internal
|
Servant.Server.Internal
|
||||||
Servant.Server.Internal.BasicAuth
|
Servant.Server.Internal.BasicAuth
|
||||||
|
@ -132,10 +133,12 @@ test-suite spec
|
||||||
main-is: Spec.hs
|
main-is: Spec.hs
|
||||||
other-modules:
|
other-modules:
|
||||||
Servant.ArbitraryMonadServerSpec
|
Servant.ArbitraryMonadServerSpec
|
||||||
|
Servant.Server.CombinatorUtilsSpec
|
||||||
Servant.Server.ErrorSpec
|
Servant.Server.ErrorSpec
|
||||||
Servant.Server.Internal.ContextSpec
|
Servant.Server.Internal.ContextSpec
|
||||||
Servant.Server.Internal.RoutingApplicationSpec
|
Servant.Server.Internal.RoutingApplicationSpec
|
||||||
Servant.Server.RouterSpec
|
Servant.Server.RouterSpec
|
||||||
|
Servant.ServerSpec
|
||||||
Servant.Server.StreamingSpec
|
Servant.Server.StreamingSpec
|
||||||
Servant.Server.UsingContextSpec
|
Servant.Server.UsingContextSpec
|
||||||
Servant.Server.UsingContextSpec.TestCombinators
|
Servant.Server.UsingContextSpec.TestCombinators
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
module Servant.Server.CombinatorUtils (
|
module Servant.Server.CombinatorUtils (
|
||||||
RouteResult(..),
|
RouteResult(..),
|
||||||
argumentCombinator,
|
argumentCombinator,
|
||||||
|
captureCombinator,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Proxy
|
import Data.Proxy
|
||||||
|
import Data.Text
|
||||||
import Network.Wai
|
import Network.Wai
|
||||||
|
|
||||||
import Servant.API
|
import Servant.API
|
||||||
|
@ -24,5 +26,19 @@ argumentCombinator ::
|
||||||
-> Delayed env (Server (combinator :> api))
|
-> Delayed env (Server (combinator :> api))
|
||||||
-> Router' env RoutingApplication
|
-> Router' env RoutingApplication
|
||||||
argumentCombinator getArg Proxy context delayed =
|
argumentCombinator getArg Proxy context delayed =
|
||||||
route (Proxy :: Proxy api) context $ addBodyCheck delayed $
|
route (Proxy :: Proxy api) context $ addBodyCheck delayed
|
||||||
DelayedIO $ \ request -> return $ getArg request
|
(DelayedIO (return ())) $ \ () ->
|
||||||
|
withRequest $ \ request -> liftRouteResult (getArg request)
|
||||||
|
|
||||||
|
captureCombinator ::
|
||||||
|
forall api combinator arg context env .
|
||||||
|
(HasServer api context) =>
|
||||||
|
(Text -> RouteResult arg)
|
||||||
|
-> Proxy (combinator :> api)
|
||||||
|
-> Context context
|
||||||
|
-> Delayed env (arg -> Server api)
|
||||||
|
-> Router' env RoutingApplication
|
||||||
|
captureCombinator getArg Proxy context delayed =
|
||||||
|
CaptureRouter $
|
||||||
|
route (Proxy :: Proxy api) context $ addCapture delayed $ \ captured ->
|
||||||
|
(liftRouteResult (getArg captured))
|
||||||
|
|
|
@ -8,12 +8,13 @@
|
||||||
|
|
||||||
module Servant.Server.CombinatorUtilsSpec where
|
module Servant.Server.CombinatorUtilsSpec where
|
||||||
|
|
||||||
import Blaze.ByteString.Builder
|
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
|
import Data.ByteString.Builder
|
||||||
import Data.ByteString.Lazy
|
import Data.ByteString.Lazy
|
||||||
import Data.Monoid
|
import Data.Monoid
|
||||||
import Data.Proxy
|
import Data.Proxy
|
||||||
import Data.String.Conversions
|
import Data.String.Conversions
|
||||||
|
import Data.Text
|
||||||
import Network.HTTP.Types
|
import Network.HTTP.Types
|
||||||
import Network.Wai
|
import Network.Wai
|
||||||
import Network.Wai.Internal
|
import Network.Wai.Internal
|
||||||
|
@ -49,10 +50,10 @@ spec :: Spec
|
||||||
spec = do
|
spec = do
|
||||||
it "allows to write a combinator by providing a function (Request -> a)" $ do
|
it "allows to write a combinator by providing a function (Request -> a)" $ do
|
||||||
let server = return
|
let server = return
|
||||||
app = serve (Proxy :: Proxy (Custom :> Get' String)) server
|
app = serve (Proxy :: Proxy (FooHeader :> Get' String)) server
|
||||||
request = defaultRequest{
|
request = defaultRequest{
|
||||||
requestHeaders =
|
requestHeaders =
|
||||||
("Custom", "foo") :
|
("FooHeader", "foo") :
|
||||||
requestHeaders defaultRequest
|
requestHeaders defaultRequest
|
||||||
}
|
}
|
||||||
response <- runApp app request
|
response <- runApp app request
|
||||||
|
@ -60,23 +61,57 @@ spec = do
|
||||||
|
|
||||||
it "allows to write a combinator the errors out" $ do
|
it "allows to write a combinator the errors out" $ do
|
||||||
let server = return
|
let server = return
|
||||||
app = serve (Proxy :: Proxy (Custom :> Get' String)) server
|
app = serve (Proxy :: Proxy (FooHeader :> Get' String)) server
|
||||||
request = defaultRequest
|
request = defaultRequest
|
||||||
response <- runApp app request
|
response <- runApp app request
|
||||||
responseStatus response `shouldBe` status400
|
responseStatus response `shouldBe` status400
|
||||||
|
|
||||||
it "allows to pick the phase of request consumption" $ do
|
it "allows to write capture combinators" $ do
|
||||||
|
let server = return
|
||||||
|
app = serve (Proxy :: Proxy (StringCapture :> Get' String)) server
|
||||||
|
request = defaultRequest{
|
||||||
|
rawPathInfo = "/foo",
|
||||||
|
pathInfo = ["foo"]
|
||||||
|
}
|
||||||
|
response <- runApp app request
|
||||||
|
responseBodyLbs response `shouldReturn` "\"foo\""
|
||||||
|
|
||||||
|
it "allows to pick the request check phase" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
it "allows to write streaming combinators for request bodies" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
it "disallows to access the request body unless in the checkBody phase" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
it "allows to access the context" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
it "allows to write combinators without args" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
it "allows to implement combinators based in terms of existing combinators" $ do
|
||||||
pending
|
pending
|
||||||
|
|
||||||
type Get' = Get '[JSON]
|
type Get' = Get '[JSON]
|
||||||
|
|
||||||
data Custom
|
data FooHeader
|
||||||
|
|
||||||
instance HasServer api context => HasServer (Custom :> api) context where
|
instance HasServer api context => HasServer (FooHeader :> api) context where
|
||||||
type ServerT (Custom :> api) m = String -> ServerT api m
|
type ServerT (FooHeader :> api) m = String -> ServerT api m
|
||||||
route = argumentCombinator getCustom
|
route = argumentCombinator getCustom
|
||||||
|
|
||||||
getCustom :: Request -> RouteResult String
|
getCustom :: Request -> RouteResult String
|
||||||
getCustom request = case lookup "Custom" (requestHeaders request) of
|
getCustom request = case lookup "FooHeader" (requestHeaders request) of
|
||||||
Nothing -> FailFatal err400
|
Nothing -> FailFatal err400
|
||||||
Just l -> Route $ cs l
|
Just l -> Route $ cs l
|
||||||
|
|
||||||
|
data StringCapture
|
||||||
|
|
||||||
|
instance HasServer api context => HasServer (StringCapture :> api) context where
|
||||||
|
type ServerT (StringCapture :> api) m = String -> ServerT api m
|
||||||
|
route = captureCombinator getCapture
|
||||||
|
|
||||||
|
getCapture :: Text -> RouteResult String
|
||||||
|
getCapture = Route . cs
|
||||||
|
|
Loading…
Reference in a new issue