on a226009 help sign in
22 files changed+33−223
since splitsnapshots
unifiedsplit
changelog.d/1571−10 changelog.d/1573−2 changelog.d/1649−8 doc/cookbook/open-id-connect/OpenIdConnect.lhs+1−1 doc/cookbook/uverb/UVerb.lhs+1−1 servant-auth/servant-auth-server/servant-auth-server.cabal−1 servant-auth/servant-auth-server/src/Servant/Auth/Server/Internal.hs+9−6 servant-auth/servant-auth-server/src/Servant/Auth/Server/Internal/AddSetCookie.hs+1−14 servant-auth/servant-auth-server/test/Servant/Auth/ServerSpec.hs+3−31 servant-auth/servant-auth/src/Servant/Auth.hs+1−1 servant-client-core/src/Servant/Client/Core/HasClient.hs+4−14 servant-conduit/servant-conduit.cabal+1−1 servant-docs/src/Servant/Docs/Internal.hs+1−1 servant-server/servant-server.cabal+3−3 servant-server/src/Servant/Server/Internal.hs+2−36 servant-server/test/Servant/ServerSpec.hs+4−47 servant/src/Servant/API.hs+1−1 servant/src/Servant/API/Raw.hs−3 servant/src/Servant/API/ResponseHeaders.hs−23 servant/src/Servant/API/UVerb.hs−3 servant/src/Servant/Links.hs+1−5 servant/test/Servant/API/ResponseHeadersSpec.hs−11
changelog.d/1571deleted−10
@@ -1,10 +0,0 @@
1−synopsis: Support UVerb in servant-auth-server
2−prs: #1571
3−issues: #1570
4−description: {
5−UVerb endpoints are now supported by servant-auth-server and can be used under the
6−Auth combinator when writing servers. It is still unsupported by
7−servant-auth-client.
8−
9−This PR also brings Headers support in UVerb responses
10−}
changelog.d/1573deleted−2
@@ -1,2 +0,0 @@
1−synopsis: Add API docs for ServerT
2−prs: #1573
changelog.d/1649deleted−8
@@ -1,8 +0,0 @@
1−synopsis: Add HasStatus instance for Headers (that defers StatusOf to underlying value)
2−prs: #1649
3−
4−description: {
5−
6−Adds a new HasStatus (Headers hs a) instance (StatusOf (Headers hs a) = StatusOf a)
7−
8−}
doc/cookbook/open-id-connect/OpenIdConnect.lhs+1−1
@@ -330,7 +330,7 @@ data Customer = Customer {
330330```
331331
332332Here is the code that displays the homepage.
333−It should contain a link to the `/login` URL.
333+It should contain a link to the the `/login` URL.
334334When the user clicks on this link it will be redirected to Google login page
335335with some generated information.
336336
doc/cookbook/uverb/UVerb.lhs+1−1
@@ -199,7 +199,7 @@ parsers in the hope that the ones that should will always error out so
199199you can try until the right one returns a value.)
200200
201201[servant-exceptions](https://github.com/ch1bo/servant-exceptions) is
202−another shot at the problem. It is inspired by
202+another shot at at the problem. It is inspired by
203203servant-checked-exceptions, so it may be worth taking a closer look.
204204The README claims that
205205[cardano-sl](https://github.com/input-output-hk/cardano-sl) also has
servant-auth/servant-auth-server/servant-auth-server.cabal−1
@@ -129,7 +129,6 @@ test-suite spec
129129 , lens-aeson >= 1.0.2 && < 1.3
130130 , warp >= 3.2.25 && < 3.4
131131 , wreq >= 0.5.2.1 && < 0.6
132− , text >= 1.2.3.0 && < 2.1
133132 other-modules:
134133 Servant.Auth.ServerSpec
135134 default-language: Haskell2010
servant-auth/servant-auth-server/src/Servant/Auth/Server/Internal.hs+9−6
@@ -54,12 +54,15 @@ instance ( n ~ 'S ('S 'Z)
5454
5555 makeCookies :: AuthResult v -> IO (SetCookieList ('S ('S 'Z)))
5656 makeCookies authResult = do
57− case authResult of
58− (Authenticated v) -> do
59− ejwt <- makeSessionCookie cookieSettings jwtSettings v
60− xsrf <- makeXsrfCookie cookieSettings
61− return $ Just xsrf `SetCookieCons` (ejwt `SetCookieCons` SetCookieNil)
62− _ -> return $ Nothing `SetCookieCons` (Nothing `SetCookieCons` SetCookieNil)
57+ xsrf <- makeXsrfCookie cookieSettings
58+ fmap (Just xsrf `SetCookieCons`) $
59+ case authResult of
60+ (Authenticated v) -> do
61+ ejwt <- makeSessionCookie cookieSettings jwtSettings v
62+ case ejwt of
63+ Nothing -> return $ Nothing `SetCookieCons` SetCookieNil
64+ Just jwt -> return $ Just jwt `SetCookieCons` SetCookieNil
65+ _ -> return $ Nothing `SetCookieCons` SetCookieNil
6366
6467 go :: (AuthResult v -> ServerT api Handler)
6568 -> (AuthResult v, SetCookieList n)
servant-auth/servant-auth-server/src/Servant/Auth/Server/Internal/AddSetCookie.hs+1−14
@@ -11,7 +11,6 @@ import Data.Tagged (Tagged (..))
1111import qualified Network.HTTP.Types as HTTP
1212import Network.Wai (mapResponseHeaders)
1313import Servant
14−import Servant.API.UVerb.Union
1514import Servant.API.Generic
1615import Servant.Server.Generic
1716import Web.Cookie
@@ -34,24 +33,12 @@ type family AddSetCookieApiVerb a where
3433 AddSetCookieApiVerb (Headers ls a) = Headers (Header "Set-Cookie" SetCookie ': ls) a
3534 AddSetCookieApiVerb a = Headers '[Header "Set-Cookie" SetCookie] a
3635
37−#if MIN_VERSION_servant_server(0,18,1)
38−type family MapAddSetCookieApiVerb (as :: [*]) where
39− MapAddSetCookieApiVerb '[] = '[]
40− MapAddSetCookieApiVerb (a ': as) = (AddSetCookieApiVerb a ': MapAddSetCookieApiVerb as)
41−#endif
42−
4336type family AddSetCookieApi a :: *
4437type instance AddSetCookieApi (a :> b) = a :> AddSetCookieApi b
4538type instance AddSetCookieApi (a :<|> b) = AddSetCookieApi a :<|> AddSetCookieApi b
46−#if MIN_VERSION_servant_server(0,19,0)
4739type instance AddSetCookieApi (NamedRoutes api) = AddSetCookieApi (ToServantApi api)
48−#endif
4940type instance AddSetCookieApi (Verb method stat ctyps a)
5041 = Verb method stat ctyps (AddSetCookieApiVerb a)
51−#if MIN_VERSION_servant_server(0,18,1)
52−type instance AddSetCookieApi (UVerb method ctyps as)
53− = UVerb method ctyps (MapAddSetCookieApiVerb as)
54−#endif
5542type instance AddSetCookieApi Raw = Raw
5643#if MIN_VERSION_servant_server(0,15,0)
5744type instance AddSetCookieApi (Stream method stat framing ctyps a)
@@ -70,7 +57,7 @@ instance {-# OVERLAPS #-} AddSetCookies ('S n) oldb newb
7057 => AddSetCookies ('S n) (a -> oldb) (a -> newb) where
7158 addSetCookies cookies oldfn = addSetCookies cookies . oldfn
7259
73−instance (orig1 ~ orig2) => AddSetCookies 'Z orig1 orig2 where
60+instance AddSetCookies 'Z orig orig where
7461 addSetCookies _ = id
7562
7663instance {-# OVERLAPPABLE #-}
servant-auth/servant-auth-server/test/Servant/Auth/ServerSpec.hs+3−31
@@ -1,5 +1,4 @@
11{-# LANGUAGE CPP #-}
2−{-# LANGUAGE TypeApplications #-}
32module Servant.Auth.ServerSpec (spec) where
43
54#if !MIN_VERSION_servant_server(0,16,0)
@@ -25,7 +24,6 @@ import Data.Aeson (FromJSON, ToJSON, Value,
2524import Data.Aeson.Lens (_JSON)
2625import qualified Data.ByteString as BS
2726import qualified Data.ByteString.Lazy as BSL
28−import Data.Text (Text, pack)
2927import Data.CaseInsensitive (mk)
3028import Data.Foldable (find)
3129import Data.Monoid
@@ -41,7 +39,6 @@ import Network.HTTP.Types (Status, status200,
4139import Network.Wai (responseLBS)
4240import Network.Wai.Handler.Warp (testWithApplication)
4341import Network.Wreq (Options, auth, basicAuth,
44− checkResponse,
4542 cookieExpiryTime, cookies,
4643 defaults, get, getWith, postWith,
4744 header, oauth2Bearer,
@@ -185,21 +182,8 @@ cookieAuthSpec
185182 it "fails with no XSRF header or cookie" $ \port -> property
186183 $ \(user :: User) -> do
187184 jwt <- createJWT theKey (newJWSHeader ((), HS256)) (claims $ toJSON user)
188− opts' <- addJwtToCookie cookieCfg jwt
189− let opts = opts' & checkResponse .~ Just mempty
190− resp <- getWith opts (url port)
191− resp ^. responseStatus `shouldBe` status401
192− (resp ^. responseCookieJar) `shouldNotHaveCookies` ["XSRF-TOKEN"]
193−
194− -- Validating that the XSRF cookie isn't added for UVerb routes either.
195− -- These routes can return a 401 response directly without using throwError / throwAll,
196− -- which revealed a bug:
197− --
198− -- https://github.com/haskell-servant/servant/issues/1570#issuecomment-1076374449
199− resp <- getWith opts (url port ++ "/uverb")
200− resp ^. responseStatus `shouldBe` status401
201− (resp ^. responseCookieJar) `shouldNotHaveCookies` ["XSRF-TOKEN"]
202−
185+ opts <- addJwtToCookie cookieCfg jwt
186+ getWith opts (url port) `shouldHTTPErrorWith` status401
203187
204188 it "succeeds if XSRF header and cookie match, and JWT is valid" $ \port -> property
205189 $ \(user :: User) -> do
@@ -421,14 +405,13 @@ type API auths
421405 = Auth auths User :>
422406 ( Get '[JSON] Int
423407 :<|> ReqBody '[JSON] Int :> Post '[JSON] Int
424− :<|> "named" :> NamedRoutes DummyRoutes
408+ :<|> NamedRoutes DummyRoutes
425409 :<|> "header" :> Get '[JSON] (Headers '[Header "Blah" Int] Int)
426410#if MIN_VERSION_servant_server(0,15,0)
427411 :<|> "stream" :> StreamGet NoFraming OctetStream (SourceIO BS.ByteString)
428412#endif
429413 :<|> "raw" :> Raw
430414 )
431− :<|> "uverb" :> Auth auths User :> UVerb 'GET '[JSON] '[WithStatus 200 Int, WithStatus 401 Text, WithStatus 403 Text]
432415 :<|> "login" :> ReqBody '[JSON] User :> Post '[JSON] (Headers '[ Header "Set-Cookie" SetCookie
433416 , Header "Set-Cookie" SetCookie ] NoContent)
434417 :<|> "logout" :> Get '[JSON] (Headers '[ Header "Set-Cookie" SetCookie
@@ -506,11 +489,6 @@ server ccfg =
506489 :<|> raw
507490 Indefinite -> throwAll err401
508491 _ -> throwAll err403
509− ) :<|>
510− (\authResult -> case authResult of
511− Authenticated usr -> respond (WithStatus @200 (42 :: Int))
512− Indefinite -> respond (WithStatus @401 $ pack "Authentication required")
513− _ -> respond (WithStatus @403 $ pack "Forbidden")
514492 )
515493 :<|> getLogin
516494 :<|> getLogout
@@ -591,12 +569,6 @@ shouldMatchCookieNames cj patterns
591569 = fmap cookie_name (destroyCookieJar cj)
592570 `shouldMatchList` patterns
593571
594−shouldNotHaveCookies :: HCli.CookieJar -> [BS.ByteString] -> Expectation
595−shouldNotHaveCookies cj patterns =
596− sequence_ $ (\cookieName -> cookieNames `shouldNotContain` [cookieName]) <$> patterns
597− where cookieNames :: [BS.ByteString]
598− cookieNames = cookie_name <$> destroyCookieJar cj
599−
600572shouldMatchCookieNameValues :: HCli.CookieJar -> [(BS.ByteString, BS.ByteString)] -> Expectation
601573shouldMatchCookieNameValues cj patterns
602574 = fmap ((,) <$> cookie_name <*> cookie_value) (destroyCookieJar cj)
servant-auth/servant-auth/src/Servant/Auth.hs+1−1
@@ -27,7 +27,7 @@ instance HasLink sub => HasLink (Auth (tag :: [*]) value :> sub) where
2727
2828-- ** Combinators
2929
30−-- | A JSON Web Token (JWT) in the Authorization header:
30+-- | A JSON Web Token (JWT) in the the Authorization header:
3131--
3232-- @Authorization: Bearer \<token\>@
3333--
servant-client-core/src/Servant/Client/Core/HasClient.hs+4−14
@@ -74,7 +74,7 @@ import Servant.API
7474 FromSourceIO (..), Header', Headers (..), HttpVersion,
7575 IsSecure, MimeRender (mimeRender),
7676 MimeUnrender (mimeUnrender), NoContent (NoContent),
77− NoContentVerb, QueryFlag, QueryParam', QueryParams, Raw, RawM,
77+ NoContentVerb, QueryFlag, QueryParam', QueryParams, Raw,
7878 ReflectMethod (..), RemoteHost, ReqBody', SBoolI, Stream,
7979 StreamBody', Summary, ToHttpApiData, ToSourceIO (..), Vault,
8080 Verb, WithNamedContext, WithResource, WithStatus (..), contentType, getHeadersHList,
@@ -674,16 +674,6 @@ instance RunClient m => HasClient m Raw where
674674
675675 hoistClientMonad _ _ f cl = \meth -> f (cl meth)
676676
677−instance RunClient m => HasClient m RawM where
678− type Client m RawM
679− = H.Method -> m Response
680−
681− clientWithRoute :: Proxy m -> Proxy RawM -> Request -> Client m RawM
682− clientWithRoute _pm Proxy req httpMethod = do
683− runRequest req { requestMethod = httpMethod }
684−
685− hoistClientMonad _ _ f cl = \meth -> f (cl meth)
686−
687677-- | If you use a 'ReqBody' in one of your endpoints in your API,
688678-- the corresponding querying function will automatically take
689679-- an additional argument of the type specified by your 'ReqBody'.
@@ -912,7 +902,7 @@ infixl 2 /:
912902-- rootClient = client api
913903--
914904-- endpointClient :: ClientM Person
915−-- endpointClient = client \/\/ subApi \/\/ endpoint
905+-- endpointClient = client // subApi // endpoint
916906-- @
917907(//) :: a -> (a -> b) -> b
918908x // f = f x
@@ -945,10 +935,10 @@ x // f = f x
945935-- rootClient = client api
946936--
947937-- hello :: String -> ClientM String
948−-- hello name = rootClient \/\/ hello \/: name
938+-- hello name = rootClient // hello /: name
949939--
950940-- endpointClient :: ClientM Person
951−-- endpointClient = client \/\/ subApi \/: "foobar123" \/\/ endpoint
941+-- endpointClient = client // subApi /: "foobar123" // endpoint
952942-- @
953943(/:) :: (a -> b -> c) -> b -> a -> c
954944(/:) = flip
servant-conduit/servant-conduit.cabal+1−1
@@ -32,7 +32,7 @@ library
3232 , bytestring >=0.10.8.1 && <0.12
3333 , conduit >=1.3.1 && <1.4
3434 , mtl ^>=2.2.2 || ^>=2.3.1
35− , resourcet >=1.2.2 && <1.4
35+ , resourcet >=1.2.2 && <1.3
3636 , servant >=0.15 && <0.20
3737 , unliftio-core >=0.1.2.0 && <0.3
3838 hs-source-dirs: src
servant-docs/src/Servant/Docs/Internal.hs+1−1
@@ -447,7 +447,7 @@ docsWith opts intros (ExtraInfo endpoints) p =
447447 & apiEndpoints %~ HM.unionWith (flip combineAction) endpoints
448448
449449
450−-- | Generate the docs for a given API that implements 'HasDocs' with any
450+-- | Generate the docs for a given API that implements 'HasDocs' with with any
451451-- number of introduction(s)
452452docsWithIntros :: HasDocs api => [DocIntro] -> Proxy api -> API
453453docsWithIntros intros = docsWith defaultDocOptions intros mempty
servant-server/servant-server.cabal+3−3
@@ -23,7 +23,7 @@ author: Servant Contributors
2323maintainer: haskell-servant-maintainers@googlegroups.com
2424copyright: 2014-2016 Zalora South East Asia Pte Ltd, 2016-2019 Servant Contributors
2525build-type: Simple
26−tested-with: GHC ==8.6.5 || ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.4 || ==9.4.3
26+tested-with: GHC ==8.6.5 || ==8.8.4 || ==8.10.2 || ==9.0.1
2727
2828extra-source-files:
2929 CHANGELOG.md
@@ -88,10 +88,10 @@ library
8888 , network >= 2.8 && < 3.2
8989 , sop-core >= 0.4.0.0 && < 0.6
9090 , string-conversions >= 0.4.0.1 && < 0.5
91− , resourcet >= 1.2.2 && < 1.4
91+ , resourcet >= 1.2.2 && < 1.3
9292 , tagged >= 0.8.6 && < 0.9
9393 , transformers-base >= 0.4.5.2 && < 0.5
94− , wai >= 3.2.2.1 && < 3.3
94+ , wai >= 3.2.1.2 && < 3.3
9595 , wai-app-static >= 3.1.6.2 && < 3.2
9696 , word8 >= 0.1.3 && < 0.2
9797
servant-server/src/Servant/Server/Internal.hs+2−36
@@ -6,7 +6,6 @@
66{-# LANGUAGE FlexibleContexts #-}
77{-# LANGUAGE FlexibleInstances #-}
88{-# LANGUAGE InstanceSigs #-}
9−{-# LANGUAGE LambdaCase #-}
109{-# LANGUAGE MultiParamTypeClasses #-}
1110{-# LANGUAGE OverloadedStrings #-}
1211{-# LANGUAGE PolyKinds #-}
@@ -66,7 +65,7 @@ import Network.HTTP.Types hiding
6665import Network.Socket
6766 (SockAddr)
6867import Network.Wai
69− (Application, Request, Response, ResponseReceived, httpVersion, isSecure, lazyRequestBody,
68+ (Application, Request, httpVersion, isSecure, lazyRequestBody,
7069 queryString, remoteHost, getRequestBodyChunk, requestHeaders,
7170 requestMethod, responseLBS, responseStream, vault)
7271import Prelude ()
@@ -76,7 +75,7 @@ import Servant.API
7675 CaptureAll, Description, EmptyAPI, Fragment,
7776 FramingRender (..), FramingUnrender (..), FromSourceIO (..),
7877 Header', If, IsSecure (..), NoContentVerb, QueryFlag,
79− QueryParam', QueryParams, Raw, RawM, ReflectMethod (reflectMethod),
78+ QueryParam', QueryParams, Raw, ReflectMethod (reflectMethod),
8079 RemoteHost, ReqBody', SBool (..), SBoolI (..), SourceIO,
8180 Stream, StreamBody', Summary, ToSourceIO (..), Vault, Verb,
8281 WithNamedContext, WithResource, NamedRoutes)
@@ -117,10 +116,6 @@ import Servant.API.TypeLevel
117116 (AtLeastOneFragment, FragmentUnique)
118117
119118class HasServer api context where
120− -- | The type of a server for this API, given a monad to run effects in.
121− --
122− -- Note that the result kind is @*@, so it is /not/ a monad transformer, unlike
123− -- what the @T@ in the name might suggest.
124119 type ServerT api (m :: * -> *) :: *
125120
126121 route ::
@@ -653,35 +648,6 @@ instance HasServer Raw context where
653648 Fail a -> respond $ Fail a
654649 FailFatal e -> respond $ FailFatal e
655650
656−-- | Just pass the request to the underlying application and serve its response.
657−--
658−-- Example:
659−--
660−-- > type MyApi = "images" :> Raw
661−-- >
662−-- > server :: Server MyApi
663−-- > server = serveDirectory "/var/www/images"
664−instance HasServer RawM context where
665− type ServerT RawM m = Request -> (Response -> IO ResponseReceived) -> m ResponseReceived
666−
667− route
668− :: Proxy RawM
669− -> Context context
670− -> Delayed env (Request -> (Response -> IO ResponseReceived) -> Handler ResponseReceived) -> Router env
671− route _ _ handleDelayed = RawRouter $ \env request respond -> runResourceT $ do
672− routeResult <- runDelayed handleDelayed env request
673− let respond' = liftIO . respond
674− liftIO $ case routeResult of
675− Route handler -> runHandler (handler request (respond . Route)) >>=
676− \case
677− Left e -> respond' $ FailFatal e
678− Right a -> pure a
679− Fail e -> respond' $ Fail e
680− FailFatal e -> respond' $ FailFatal e
681−
682− hoistServerWithContext _ _ f srvM = \req respond -> f (srvM req respond)
683−
684−
685651-- | If you use 'ReqBody' in one of the endpoints for your API,
686652-- this automatically requires your server-side handler to be a function
687653-- that takes an argument of the type specified by 'ReqBody'.
servant-server/test/Servant/ServerSpec.hs+4−47
@@ -17,10 +17,8 @@ import Prelude.Compat
1717
1818import Control.Monad
1919 (forM_, unless, when)
20−import Control.Monad.Reader (runReaderT, ask)
2120import Control.Monad.Error.Class
2221 (MonadError (..))
23−import Control.Monad.IO.Class (MonadIO(..))
2422import Data.Aeson
2523 (FromJSON, ToJSON, decode', encode)
2624import Data.Acquire
@@ -56,19 +54,19 @@ import Servant.API
5654 Delete, EmptyAPI, Fragment, Get, HasStatus (StatusOf), Header,
5755 Headers, HttpVersion, IsSecure (..), JSON, Lenient,
5856 NoContent (..), NoContentVerb, NoFraming, OctetStream, Patch,
59− PlainText, Post, Put, QueryFlag, QueryParam, QueryParams, Raw, RawM,
57+ PlainText, Post, Put, QueryFlag, QueryParam, QueryParams, Raw,
6058 RemoteHost, ReqBody, SourceIO, StdMethod (..), Stream, Strict,
6159 UVerb, Union, Verb, WithStatus (..), addHeader)
6260import Servant.Server
63− (Context ((:.), EmptyContext), Handler, Server, ServerT, Tagged (..),
64− emptyServer, err401, err403, err404, hoistServer, respond, serve,
61+ (Context ((:.), EmptyContext), Handler, Server, Tagged (..),
62+ emptyServer, err401, err403, err404, respond, serve,
6563 serveWithContext)
6664import Servant.Test.ComprehensiveAPI
6765import qualified Servant.Types.SourceT as S
6866import Test.Hspec
6967 (Spec, context, describe, it, shouldBe, shouldContain)
7068import Test.Hspec.Wai
71− (get, matchHeaders, matchStatus, shouldRespondWith,
69+ (get, liftIO, matchHeaders, matchStatus, shouldRespondWith,
7270 with, (<:>))
7371import qualified Test.Hspec.Wai as THW
7472
@@ -104,7 +102,6 @@ spec = do
104102 reqBodySpec
105103 headerSpec
106104 rawSpec
107− rawMSpec
108105 alternativeSpec
109106 responseHeadersSpec
110107 uverbResponseHeadersSpec
@@ -613,46 +610,6 @@ rawSpec = do
613610
614611-- }}}
615612------------------------------------------------------------------------------
616−-- * rawMSpec {{{
617−------------------------------------------------------------------------------
618−
619−type RawMApi = "foo" :> RawM
620−
621−rawMApi :: Proxy RawMApi
622−rawMApi = Proxy
623−
624−rawMServer :: (Monad m, MonadIO m, Show a) => (Request -> m a) -> ServerT RawMApi m
625−rawMServer f req resp = liftIO . resp . responseLBS ok200 [] . cs . show =<< f req
626−
627−rawMSpec :: Spec
628−rawMSpec = do
629− describe "Servant.API.RawM" $ do
630− it "gives access to monadic context" $ do
631− flip runSession (serve rawMApi
632− (hoistServer rawMApi (flip runReaderT (42 :: Integer)) (rawMServer (const ask)))) $ do
633− response <- Network.Wai.Test.request defaultRequest{
634− pathInfo = ["foo"]
635− }
636− liftIO $ do
637− simpleBody response `shouldBe` "42"
638−
639− it "lets users throw servant errors" $ do
640− flip runSession (serve rawMApi (rawMServer (const $ throwError err404 >> pure (42 :: Integer)))) $ do
641− response <- Network.Wai.Test.request defaultRequest{
642− pathInfo = ["foo"]
643− }
644− liftIO $ do
645− statusCode (simpleStatus response) `shouldBe` 404
646−
647− it "gets the pathInfo modified" $ do
648− flip runSession (serve rawMApi (rawMServer (pure . pathInfo))) $ do
649− response <- Network.Wai.Test.request defaultRequest{
650− pathInfo = ["foo", "bar"]
651− }
652− liftIO $ do
653− simpleBody response `shouldBe` cs (show ["bar" :: String])
654−-- }}}
655−------------------------------------------------------------------------------
656613-- * alternativeSpec {{{
657614------------------------------------------------------------------------------
658615type AlternativeApi =
servant/src/Servant/API.hs+1−1
@@ -119,7 +119,7 @@ import Servant.API.NamedRoutes
119119import Servant.API.QueryParam
120120 (QueryFlag, QueryParam, QueryParam', QueryParams)
121121import Servant.API.Raw
122− (Raw, RawM)
122+ (Raw)
123123import Servant.API.RemoteHost
124124 (RemoteHost)
125125import Servant.API.ReqBody
servant/src/Servant/API/Raw.hs−3
@@ -15,6 +15,3 @@ import Data.Typeable
1515-- <https://hackage.haskell.org/package/servant-server/docs/Servant-Server-StaticFiles.html Servant.Server.StaticFiles>
1616-- to serve static files stored in a particular directory on your filesystem
1717data Raw deriving Typeable
18−
19−-- | Variant of 'Raw' that lets you access the underlying monadic context to process the request.
20−data RawM deriving Typeable
servant/src/Servant/API/ResponseHeaders.hs−23
@@ -8,7 +8,6 @@
88{-# LANGUAGE PolyKinds #-}
99{-# LANGUAGE ScopedTypeVariables #-}
1010{-# LANGUAGE TypeFamilies #-}
11−{-# LANGUAGE TypeFamilyDependencies #-}
1211{-# LANGUAGE TypeOperators #-}
1312{-# LANGUAGE UndecidableInstances #-}
1413{-# OPTIONS_HADDOCK not-home #-}
@@ -52,9 +51,6 @@ import Prelude ()
5251import Prelude.Compat
5352import Servant.API.Header
5453 (Header)
55−import Servant.API.UVerb.Union
56−import qualified Data.SOP.BasicFunctors as SOP
57−import qualified Data.SOP.NS as SOP
5854
5955-- | Response Header objects. You should never need to construct one directly.
6056-- Instead, use 'addOptionalHeader'.
@@ -174,25 +170,6 @@ instance {-# OVERLAPPABLE #-} ( KnownSymbol h, ToHttpApiData v , new ~ Headers '
174170 => AddHeader h v a new where
175171 addOptionalHeader hdr resp = Headers resp (HCons hdr HNil)
176172
177−-- Instances to decorate all responses in a 'Union' with headers. The functional
178−-- dependencies force us to consider singleton lists as the base case in the
179−-- recursion (it is impossible to determine h and v otherwise from old / new
180−-- responses if the list is empty).
181−instance (AddHeader h v old new) => AddHeader h v (Union '[old]) (Union '[new]) where
182− addOptionalHeader hdr resp =
183− SOP.Z $ SOP.I $ addOptionalHeader hdr $ SOP.unI $ SOP.unZ $ resp
184−
185−instance
186− ( AddHeader h v old new, AddHeader h v (Union oldrest) (Union newrest)
187− -- This ensures that the remainder of the response list is _not_ empty
188− -- It is necessary to prevent the two instances for union types from
189− -- overlapping.
190− , oldrest ~ (a ': as), newrest ~ (b ': bs))
191− => AddHeader h v (Union (old ': (a ': as))) (Union (new ': (b ': bs))) where
192− addOptionalHeader hdr resp = case resp of
193− SOP.Z (SOP.I rHead) -> SOP.Z $ SOP.I $ addOptionalHeader hdr rHead
194− SOP.S rOthers -> SOP.S $ addOptionalHeader hdr rOthers
195−
196173-- | @addHeader@ adds a header to a response. Note that it changes the type of
197174-- the value in the following ways:
198175--
servant/src/Servant/API/UVerb.hs−3
@@ -38,7 +38,6 @@ import GHC.TypeLits (Nat)
3838import Network.HTTP.Types (Status, StdMethod)
3939import Servant.API.ContentTypes (JSON, PlainText, FormUrlEncoded, OctetStream, NoContent, MimeRender(mimeRender), MimeUnrender(mimeUnrender))
4040import Servant.API.Status (KnownStatus, statusVal)
41−import Servant.API.ResponseHeaders (Headers)
4241import Servant.API.UVerb.Union
4342
4443class KnownStatus (StatusOf a) => HasStatus (a :: *) where
@@ -87,8 +86,6 @@ newtype WithStatus (k :: Nat) a = WithStatus a
8786instance KnownStatus n => HasStatus (WithStatus n a) where
8887 type StatusOf (WithStatus n a) = n
8988
90−instance HasStatus a => HasStatus (Headers ls a) where
91− type StatusOf (Headers ls a) = StatusOf a
9289
9390-- | A variant of 'Verb' that can have any of a number of response values and status codes.
9491--
servant/src/Servant/Links.hs+1−5
@@ -175,7 +175,7 @@ import Servant.API.NamedRoutes
175175import Servant.API.QueryParam
176176 (QueryFlag, QueryParam', QueryParams)
177177import Servant.API.Raw
178− (Raw, RawM)
178+ (Raw)
179179import Servant.API.RemoteHost
180180 (RemoteHost)
181181import Servant.API.ReqBody
@@ -589,10 +589,6 @@ instance HasLink Raw where
589589 type MkLink Raw a = a
590590 toLink toA _ = toA
591591
592−instance HasLink RawM where
593− type MkLink RawM a = a
594− toLink toA _ = toA
595−
596592instance HasLink (Stream m status fr ct a) where
597593 type MkLink (Stream m status fr ct a) r = r
598594 toLink toA _ = toA
servant/test/Servant/API/ResponseHeadersSpec.hs−11
@@ -2,14 +2,10 @@
22{-# LANGUAGE OverloadedStrings #-}
33module Servant.API.ResponseHeadersSpec where
44
5−import Data.Proxy
6−import GHC.TypeLits
75import Test.Hspec
86
9−import Servant.API.ContentTypes
107import Servant.API.Header
118import Servant.API.ResponseHeaders
12−import Servant.API.UVerb
139
1410spec :: Spec
1511spec = describe "Servant.API.ResponseHeaders" $ do
@@ -32,10 +28,3 @@ spec = describe "Servant.API.ResponseHeaders" $ do
3228 it "does not add a header" $ do
3329 let val = noHeader 5 :: Headers '[Header "test" Int] Int
3430 getHeaders val `shouldBe` []
35−
36− describe "HasStatus Headers" $ do
37−
38− it "gets the status from the underlying value" $ do
39− natVal (Proxy :: Proxy (StatusOf (Headers '[Header "first" Int] NoContent))) `shouldBe` 204
40− natVal (Proxy :: Proxy (StatusOf (Headers '[Header "first" Int] (WithStatus 503 ())))) `shouldBe` 503
41−