on master help sign in
Introduce a `Handler` alias for `ExceptT ServantErr IO`
2154699Luke Cycon
doc/tutorial/Authentication.lhs+10−11
@@ -44,7 +44,6 @@ You can use this combinator to protect an API as follows:
44
44
45module Authentication where
45module Authentication where
46
46
47−import Control.Monad.Trans.Except (ExceptT)
48import Data.Aeson (ToJSON)
47import Data.Aeson (ToJSON)
49import Data.ByteString (ByteString)
48import Data.ByteString (ByteString)
50import Data.Map (Map, fromList)
49import Data.Map (Map, fromList)
@@ -66,7 +65,7 @@ import Servant.Server (BasicAuthCheck (BasicAuthCheck),
66 ),
65 ),
67 Context ((:.), EmptyContext),
66 Context ((:.), EmptyContext),
68 err401, err403, errBody, Server,
67 err401, err403, errBody, Server,
69− ServantErr, serveWithContext)
68+ serveWithContext, Handler)
70import Servant.Server.Experimental.Auth (AuthHandler, AuthServerData,
69import Servant.Server.Experimental.Auth (AuthHandler, AuthServerData,
71 mkAuthHandler)
70 mkAuthHandler)
72import Servant.Server.Experimental.Auth()
71import Servant.Server.Experimental.Auth()
@@ -118,22 +117,22 @@ or dictated the structure of a response (e.g. a `Capture` param is pulled from
118the request path). Now consider an API resource protected by basic
117the request path). Now consider an API resource protected by basic
119authentication. Once the required `WWW-Authenticate` header is checked, we need
118authentication. Once the required `WWW-Authenticate` header is checked, we need
120to verify the username and password. But how? One solution would be to force an
119to verify the username and password. But how? One solution would be to force an
121−API author to provide a function of type `BasicAuthData -> ExceptT ServantErr IO User`
120+API author to provide a function of type `BasicAuthData -> Handler User`
122and servant should use this function to authenticate a request. Unfortunately
121and servant should use this function to authenticate a request. Unfortunately
123this didn't work prior to `0.5` because all of servant's machinery was
122this didn't work prior to `0.5` because all of servant's machinery was
124engineered around the idea that each combinator can extract information from
123engineered around the idea that each combinator can extract information from
125only the request. We cannot extract the function
124only the request. We cannot extract the function
126−`BasicAuthData -> ExceptT ServantErr IO User` from a request! Are we doomed?
125+`BasicAuthData -> Handler User` from a request! Are we doomed?
127
126
128Servant `0.5` introduced `Context` to handle this. The type machinery is beyond
127Servant `0.5` introduced `Context` to handle this. The type machinery is beyond
129the scope of this tutorial, but the idea is simple: provide some data to the
128the scope of this tutorial, but the idea is simple: provide some data to the
130`serve` function, and that data is propagated to the functions that handle each
129`serve` function, and that data is propagated to the functions that handle each
131combinator. Using `Context`, we can supply a function of type
130combinator. Using `Context`, we can supply a function of type
132−`BasicAuthData -> ExceptT ServantErr IO User` to the `BasicAuth` combinator
131+`BasicAuthData -> Handler User` to the `BasicAuth` combinator
133handler. This will allow the handler to check authentication and return a `User`
132handler. This will allow the handler to check authentication and return a `User`
134to downstream handlers if successful.
133to downstream handlers if successful.
135
134
136−In practice we wrap `BasicAuthData -> ExceptT ServantErr IO` into a slightly
135+In practice we wrap `BasicAuthData -> Handler` into a slightly
137different function to better capture the semantics of basic authentication:
136different function to better capture the semantics of basic authentication:
138
137
139``` haskell ignore
138``` haskell ignore
@@ -247,7 +246,7 @@ your feedback!
247### What is Generalized Authentication?
246### What is Generalized Authentication?
248
247
249**TL;DR**: you throw a tagged `AuthProtect` combinator in front of the endpoints
248**TL;DR**: you throw a tagged `AuthProtect` combinator in front of the endpoints
250−you want protected and then supply a function `Request -> ExceptT IO ServantErr user`
249+you want protected and then supply a function `Request -> Handler user`
251which we run anytime a request matches a protected endpoint. It precisely solves
250which we run anytime a request matches a protected endpoint. It precisely solves
252the "I just need to protect these endpoints with a function that does some
251the "I just need to protect these endpoints with a function that does some
253complicated business logic" and nothing more. Behind the scenes we use a type
252complicated business logic" and nothing more. Behind the scenes we use a type
@@ -273,19 +272,19 @@ database = fromList [ ("key1", Account "Anne Briggs")
273
272
274-- | A method that, when given a password, will return a Account.
273-- | A method that, when given a password, will return a Account.
275-- This is our bespoke (and bad) authentication logic.
274-- This is our bespoke (and bad) authentication logic.
276−lookupAccount :: ByteString -> ExceptT ServantErr IO Account
275+lookupAccount :: ByteString -> Handler Account
277lookupAccount key = case Map.lookup key database of
276lookupAccount key = case Map.lookup key database of
278 Nothing -> throwError (err403 { errBody = "Invalid Cookie" })
277 Nothing -> throwError (err403 { errBody = "Invalid Cookie" })
279 Just usr -> return usr
278 Just usr -> return usr
280```
279```
281
280
282For generalized authentication, servant exposes the `AuthHandler` type,
281For generalized authentication, servant exposes the `AuthHandler` type,
283−which is used to wrap the `Request -> ExceptT IO ServantErr user` logic. Let's
282+which is used to wrap the `Request -> Handler user` logic. Let's
284create a value of type `AuthHandler Request Account` using the above `lookupAccount`
283create a value of type `AuthHandler Request Account` using the above `lookupAccount`
285method:
284method:
286
285
287```haskell
286```haskell
288−-- | The auth handler wraps a function from Request -> ExceptT ServantErr IO Account
287+-- | The auth handler wraps a function from Request -> Handler Account
289-- we look for a Cookie and pass the value of the cookie to `lookupAccount`.
288-- we look for a Cookie and pass the value of the cookie to `lookupAccount`.
290authHandler :: AuthHandler Request Account
289authHandler :: AuthHandler Request Account
291authHandler =
290authHandler =
@@ -380,7 +379,7 @@ forward:
3802. choose a application-specific data type used by your server when
3792. choose a application-specific data type used by your server when
381authentication is successful (in our case this was `User`).
380authentication is successful (in our case this was `User`).
3823. Create a value of `AuthHandler Request User` which encapsulates the
3813. Create a value of `AuthHandler Request User` which encapsulates the
383−authentication logic (`Request -> ExceptT IO ServantErr User`). This function
382+authentication logic (`Request -> Handler User`). This function
384will be executed everytime a request matches a protected route.
383will be executed everytime a request matches a protected route.
3854. Provide an instance of the `AuthServerData` type family, specifying your
3844. Provide an instance of the `AuthServerData` type family, specifying your
386application-specific data type returned when authentication is successful (in
385application-specific data type returned when authentication is successful (in
doc/tutorial/Server.lhs+41−45
@@ -111,11 +111,11 @@ corresponding API type.
111The first thing to know about the `Server` type family is that behind the
111The first thing to know about the `Server` type family is that behind the
112scenes it will drive the routing, letting you focus only on the business
112scenes it will drive the routing, letting you focus only on the business
113logic. The second thing to know is that for each endpoint, your handlers will
113logic. The second thing to know is that for each endpoint, your handlers will
114−by default run in the `ExceptT ServantErr IO` monad. This is overridable very
114+by default run in the `Handler` monad. This is overridable very
115easily, as explained near the end of this guide. Third thing, the type of the
115easily, as explained near the end of this guide. Third thing, the type of the
116value returned in that monad must be the same as the second argument of the
116value returned in that monad must be the same as the second argument of the
117HTTP method combinator used for the corresponding endpoint. In our case, it
117HTTP method combinator used for the corresponding endpoint. In our case, it
118−means we must provide a handler of type `ExceptT ServantErr IO [User]`. Well,
118+means we must provide a handler of type `Handler [User]`. Well,
119we have a monad, let's just `return` our list:
119we have a monad, let's just `return` our list:
120
120
121``` haskell
121``` haskell
@@ -269,15 +269,15 @@ server3 = position
269 :<|> hello
269 :<|> hello
270 :<|> marketing
270 :<|> marketing
271
271
272− where position :: Int -> Int -> ExceptT ServantErr IO Position
272+ where position :: Int -> Int -> Handler Position
273 position x y = return (Position x y)
273 position x y = return (Position x y)
274
274
275− hello :: Maybe String -> ExceptT ServantErr IO HelloMessage
275+ hello :: Maybe String -> Handler HelloMessage
276 hello mname = return . HelloMessage $ case mname of
276 hello mname = return . HelloMessage $ case mname of
277 Nothing -> "Hello, anonymous coward"
277 Nothing -> "Hello, anonymous coward"
278 Just n -> "Hello, " ++ n
278 Just n -> "Hello, " ++ n
279
279
280− marketing :: ClientInfo -> ExceptT ServantErr IO Email
280+ marketing :: ClientInfo -> Handler Email
281 marketing clientinfo = return (emailForClient clientinfo)
281 marketing clientinfo = return (emailForClient clientinfo)
282```
282```
283
283
@@ -307,7 +307,7 @@ $ curl -X POST -d '{"clientName":"Alp Mestanogullari", "clientEmail" : "alp@foo.
307
307
308For reference, here's a list of some combinators from **servant**:
308For reference, here's a list of some combinators from **servant**:
309
309
310− > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `ExceptT ServantErr IO <something>`.
310+ > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `Handler <something>`.
311 > - `Capture "something" a` becomes an argument of type `a`.
311 > - `Capture "something" a` becomes an argument of type `a`.
312 > - `QueryParam "something" a`, `Header "something" a` all become arguments of type `Maybe a`, because there might be no value at all specified by the client for these.
312 > - `QueryParam "something" a`, `Header "something" a` all become arguments of type `Maybe a`, because there might be no value at all specified by the client for these.
313 > - `QueryFlag "something"` gets turned into an argument of type `Bool`.
313 > - `QueryFlag "something"` gets turned into an argument of type `Bool`.
@@ -601,11 +601,10 @@ $ curl -H 'Accept: text/html' http://localhost:8081/persons
601# or just point your browser to http://localhost:8081/persons
601# or just point your browser to http://localhost:8081/persons
602```
602```
603
603
604−## The `ExceptT ServantErr IO` monad
604+## The `Handler` monad
605
605
606−At the heart of the handlers is the monad they run in, namely `ExceptT
606+At the heart of the handlers is the monad they run in, namely `ExceptT ServantErr IO`
607−ServantErr IO`
608−([haddock documentation for `ExceptT`](http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#t:ExceptT)).
607+([haddock documentation for `ExceptT`](http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#t:ExceptT)), which is aliased as `Handler`.
609One might wonder: why this monad? The answer is that it is the
608One might wonder: why this monad? The answer is that it is the
610simplest monad with the following properties:
609simplest monad with the following properties:
611
610
@@ -621,7 +620,7 @@ Let's recall some definitions.
621newtype ExceptT e m a = ExceptT (m (Either e a))
620newtype ExceptT e m a = ExceptT (m (Either e a))
622```
621```
623
622
624−In short, this means that a handler of type `ExceptT ServantErr IO a` is simply
623+In short, this means that a handler of type `Handler a` is simply
625equivalent to a computation of type `IO (Either ServantErr a)`, that is, an IO
624equivalent to a computation of type `IO (Either ServantErr a)`, that is, an IO
626action that either returns an error or a result.
625action that either returns an error or a result.
627
626
@@ -688,7 +687,7 @@ module. If you want to use these values but add a body or some headers, just
688use record update syntax:
687use record update syntax:
689
688
690``` haskell
689``` haskell
691−failingHandler :: ExceptT ServantErr IO ()
690+failingHandler :: Handler ()
692failingHandler = throwError myerr
691failingHandler = throwError myerr
693
692
694 where myerr :: ServantErr
693 where myerr :: ServantErr
@@ -826,11 +825,11 @@ However, you have to be aware that this has an effect on the type of the
826corresponding `Server`:
825corresponding `Server`:
827
826
828``` haskell ignore
827``` haskell ignore
829−Server UserAPI3 = (Int -> ExceptT ServantErr IO User)
828+Server UserAPI3 = (Int -> Handler User)
830− :<|> (Int -> ExceptT ServantErr IO ())
829+ :<|> (Int -> Handler ())
831
830
832−Server UserAPI4 = Int -> ( ExceptT ServantErr IO User
831+Server UserAPI4 = Int -> ( Handler User
833− :<|> ExceptT ServantErr IO ()
832+ :<|> Handler ()
834 )
833 )
835```
834```
836
835
@@ -842,10 +841,10 @@ computations in `ExceptT`, with no arguments. In other words:
842server8 :: Server UserAPI3
841server8 :: Server UserAPI3
843server8 = getUser :<|> deleteUser
842server8 = getUser :<|> deleteUser
844
843
845− where getUser :: Int -> ExceptT ServantErr IO User
844+ where getUser :: Int -> Handler User
846 getUser _userid = error "..."
845 getUser _userid = error "..."
847
846
848− deleteUser :: Int -> ExceptT ServantErr IO ()
847+ deleteUser :: Int -> Handler ()
849 deleteUser _userid = error "..."
848 deleteUser _userid = error "..."
850
849
851-- notice how getUser and deleteUser
850-- notice how getUser and deleteUser
@@ -854,10 +853,10 @@ server8 = getUser :<|> deleteUser
854server9 :: Server UserAPI4
853server9 :: Server UserAPI4
855server9 userid = getUser userid :<|> deleteUser userid
854server9 userid = getUser userid :<|> deleteUser userid
856
855
857− where getUser :: Int -> ExceptT ServantErr IO User
856+ where getUser :: Int -> Handler User
858 getUser = error "..."
857 getUser = error "..."
859
858
860− deleteUser :: Int -> ExceptT ServantErr IO ()
859+ deleteUser :: Int -> Handler ()
861 deleteUser = error "..."
860 deleteUser = error "..."
862```
861```
863
862
@@ -905,23 +904,23 @@ type UsersAPI =
905usersServer :: Server UsersAPI
904usersServer :: Server UsersAPI
906usersServer = getUsers :<|> newUser :<|> userOperations
905usersServer = getUsers :<|> newUser :<|> userOperations
907
906
908− where getUsers :: ExceptT ServantErr IO [User]
907+ where getUsers :: Handler [User]
909 getUsers = error "..."
908 getUsers = error "..."
910
909
911− newUser :: User -> ExceptT ServantErr IO ()
910+ newUser :: User -> Handler ()
912 newUser = error "..."
911 newUser = error "..."
913
912
914 userOperations userid =
913 userOperations userid =
915 viewUser userid :<|> updateUser userid :<|> deleteUser userid
914 viewUser userid :<|> updateUser userid :<|> deleteUser userid
916
915
917 where
916 where
918− viewUser :: Int -> ExceptT ServantErr IO User
917+ viewUser :: Int -> Handler User
919 viewUser = error "..."
918 viewUser = error "..."
920
919
921− updateUser :: Int -> User -> ExceptT ServantErr IO ()
920+ updateUser :: Int -> User -> Handler ()
922 updateUser = error "..."
921 updateUser = error "..."
923
922
924− deleteUser :: Int -> ExceptT ServantErr IO ()
923+ deleteUser :: Int -> Handler ()
925 deleteUser = error "..."
924 deleteUser = error "..."
926```
925```
927
926
@@ -940,23 +939,23 @@ data Product = Product { productId :: Int }
940productsServer :: Server ProductsAPI
939productsServer :: Server ProductsAPI
941productsServer = getProducts :<|> newProduct :<|> productOperations
940productsServer = getProducts :<|> newProduct :<|> productOperations
942
941
943− where getProducts :: ExceptT ServantErr IO [Product]
942+ where getProducts :: Handler [Product]
944 getProducts = error "..."
943 getProducts = error "..."
945
944
946− newProduct :: Product -> ExceptT ServantErr IO ()
945+ newProduct :: Product -> Handler ()
947 newProduct = error "..."
946 newProduct = error "..."
948
947
949 productOperations productid =
948 productOperations productid =
950 viewProduct productid :<|> updateProduct productid :<|> deleteProduct productid
949 viewProduct productid :<|> updateProduct productid :<|> deleteProduct productid
951
950
952 where
951 where
953− viewProduct :: Int -> ExceptT ServantErr IO Product
952+ viewProduct :: Int -> Handler Product
954 viewProduct = error "..."
953 viewProduct = error "..."
955
954
956− updateProduct :: Int -> Product -> ExceptT ServantErr IO ()
955+ updateProduct :: Int -> Product -> Handler ()
957 updateProduct = error "..."
956 updateProduct = error "..."
958
957
959− deleteProduct :: Int -> ExceptT ServantErr IO ()
958+ deleteProduct :: Int -> Handler ()
960 deleteProduct = error "..."
959 deleteProduct = error "..."
961```
960```
962
961
@@ -985,11 +984,11 @@ type APIFor a i =
985
984
986-- Build the appropriate 'Server'
985-- Build the appropriate 'Server'
987-- given the handlers of the right type.
986-- given the handlers of the right type.
988−serverFor :: ExceptT ServantErr IO [a] -- handler for listing of 'a's
987+serverFor :: Handler [a] -- handler for listing of 'a's
989− -> (a -> ExceptT ServantErr IO ()) -- handler for adding an 'a'
988+ -> (a -> Handler ()) -- handler for adding an 'a'
990− -> (i -> ExceptT ServantErr IO a) -- handler for viewing an 'a' given its identifier of type 'i'
989+ -> (i -> Handler a) -- handler for viewing an 'a' given its identifier of type 'i'
991− -> (i -> a -> ExceptT ServantErr IO ()) -- updating an 'a' with given id
990+ -> (i -> a -> Handler ()) -- updating an 'a' with given id
992− -> (i -> ExceptT ServantErr IO ()) -- deleting an 'a' given its id
991+ -> (i -> Handler ()) -- deleting an 'a' given its id
993 -> Server (APIFor a i)
992 -> Server (APIFor a i)
994serverFor = error "..."
993serverFor = error "..."
995-- implementation left as an exercise. contact us on IRC
994-- implementation left as an exercise. contact us on IRC
@@ -998,12 +997,11 @@ serverFor = error "..."
998
997
999## Using another monad for your handlers
998## Using another monad for your handlers
1000
999
1001−Remember how `Server` turns combinators for HTTP methods into `ExceptT
1000+Remember how `Server` turns combinators for HTTP methods into `Handler`? Well, actually, there's more to that. `Server` is actually a
1002−ServantErr IO`? Well, actually, there's more to that. `Server` is actually a
1003simple type synonym.
1001simple type synonym.
1004
1002
1005``` haskell ignore
1003``` haskell ignore
1006−type Server api = ServerT api (ExceptT ServantErr IO)
1004+type Server api = ServerT api Handler
1007```
1005```
1008
1006
1009`ServerT` is the actual type family that computes the required types for the
1007`ServerT` is the actual type family that computes the required types for the
@@ -1036,12 +1034,11 @@ listToMaybeNat = Nat listToMaybe -- from Data.Maybe
1036
1034
1037(`Nat` comes from "natural transformation", in case you're wondering.)
1035(`Nat` comes from "natural transformation", in case you're wondering.)
1038
1036
1039−So if you want to write handlers using another monad/type than `ExceptT
1037+So if you want to write handlers using another monad/type than `Handler`, say the `Reader String` monad, the first thing you have to
1040−ServantErr IO`, say the `Reader String` monad, the first thing you have to
1041prepare is a function:
1038prepare is a function:
1042
1039
1043``` haskell ignore
1040``` haskell ignore
1044−readerToHandler :: Reader String :~> ExceptT ServantErr IO
1041+readerToHandler :: Reader String :~> Handler
1045```
1042```
1046
1043
1047Let's start with `readerToHandler'`. We obviously have to run the `Reader`
1044Let's start with `readerToHandler'`. We obviously have to run the `Reader`
@@ -1050,10 +1047,10 @@ from that and can then just `return` it into `ExceptT`. We can then just wrap
1050that function with the `Nat` constructor to make it have the fancier type.
1047that function with the `Nat` constructor to make it have the fancier type.
1051
1048
1052``` haskell
1049``` haskell
1053−readerToHandler' :: forall a. Reader String a -> ExceptT ServantErr IO a
1050+readerToHandler' :: forall a. Reader String a -> Handler a
1054readerToHandler' r = return (runReader r "hi")
1051readerToHandler' r = return (runReader r "hi")
1055
1052
1056−readerToHandler :: Reader String :~> ExceptT ServantErr IO
1053+readerToHandler :: Reader String :~> Handler
1057readerToHandler = Nat readerToHandler'
1054readerToHandler = Nat readerToHandler'
1058```
1055```
1059
1056
@@ -1077,8 +1074,7 @@ readerServerT = a :<|> b
1077```
1074```
1078
1075
1079We unfortunately can't use `readerServerT` as an argument of `serve`, because
1076We unfortunately can't use `readerServerT` as an argument of `serve`, because
1080−`serve` wants a `Server ReaderAPI`, i.e., with handlers running in `ExceptT
1077+`serve` wants a `Server ReaderAPI`, i.e., with handlers running in `Handler`. But there's a simple solution to this.
1081−ServantErr IO`. But there's a simple solution to this.
1082
1078
1083### Enter `enter`
1079### Enter `enter`
1084
1080
servant-client/test/Servant/ClientSpec.hs+1−1
@@ -355,7 +355,7 @@ failSpec = beforeAll (startWaiApp failServer) $ afterAll endWaiApp $ do
355 _ -> fail $ "expected InvalidContentTypeHeader, but got " <> show res
355 _ -> fail $ "expected InvalidContentTypeHeader, but got " <> show res
356
356
357data WrappedApi where
357data WrappedApi where
358− WrappedApi :: (HasServer (api :: *) '[], Server api ~ ExceptT ServantErr IO a,
358+ WrappedApi :: (HasServer (api :: *) '[], Server api ~ Handler a,
359 HasClient api, Client api ~ (C.Manager -> BaseUrl -> SCR.ClientM ())) =>
359 HasClient api, Client api ~ (C.Manager -> BaseUrl -> SCR.ClientM ())) =>
360 Proxy api -> WrappedApi
360 Proxy api -> WrappedApi
361
361
servant-mock/src/Servant/Mock.hs+2−2
@@ -97,8 +97,8 @@ class HasServer api context => HasMock api context where
97 -- actually "means" 2 request handlers, of the following types:
97 -- actually "means" 2 request handlers, of the following types:
98 --
98 --
99 -- @
99 -- @
100− -- getUser :: ExceptT ServantErr IO User
100+ -- getUser :: Handler User
101− -- getBook :: ExceptT ServantErr IO Book
101+ -- getBook :: Handler Book
102 -- @
102 -- @
103 --
103 --
104 -- So under the hood, 'mock' uses the 'IO' bit to generate
104 -- So under the hood, 'mock' uses the 'IO' bit to generate
servant-server/example/greet.hs+1−1
@@ -44,7 +44,7 @@ testApi = Proxy
44-- There's one handler per endpoint, which, just like in the type
44-- There's one handler per endpoint, which, just like in the type
45-- that represents the API, are glued together using :<|>.
45-- that represents the API, are glued together using :<|>.
46--
46--
47−-- Each handler runs in the 'ExceptT ServantErr IO' monad.
47+-- Each handler runs in the 'Handler' monad.
48server :: Server TestApi
48server :: Server TestApi
49server = helloH :<|> postGreetH :<|> deleteGreetH
49server = helloH :<|> postGreetH :<|> deleteGreetH
50
50
servant-server/src/Servant/Server.hs+1
@@ -17,6 +17,7 @@ module Servant.Server
17 , -- * Handlers for all standard combinators
17 , -- * Handlers for all standard combinators
18 HasServer(..)
18 HasServer(..)
19 , Server
19 , Server
20+ , Handler
20
21
21 -- * Debugging the server layout
22 -- * Debugging the server layout
22 , layout
23 , layout
servant-server/src/Servant/Server/Experimental/Auth.hs+4−5
@@ -12,8 +12,7 @@
12
12
13module Servant.Server.Experimental.Auth where
13module Servant.Server.Experimental.Auth where
14
14
15−import Control.Monad.Trans.Except (ExceptT,
15+import Control.Monad.Trans.Except (runExceptT)
16− runExceptT)
17import Data.Proxy (Proxy (Proxy))
16import Data.Proxy (Proxy (Proxy))
18import Data.Typeable (Typeable)
17import Data.Typeable (Typeable)
19import GHC.Generics (Generic)
18import GHC.Generics (Generic)
@@ -28,7 +27,7 @@ import Servant.Server.Internal (HasContextEntry,
28import Servant.Server.Internal.Router (Router' (WithRequest))
27import Servant.Server.Internal.Router (Router' (WithRequest))
29import Servant.Server.Internal.RoutingApplication (RouteResult (FailFatal, Route),
28import Servant.Server.Internal.RoutingApplication (RouteResult (FailFatal, Route),
30 addAuthCheck)
29 addAuthCheck)
31−import Servant.Server.Internal.ServantErr (ServantErr)
30+import Servant.Server.Internal.ServantErr (ServantErr, Handler)
32
31
33-- * General Auth
32-- * General Auth
34
33
@@ -42,11 +41,11 @@ type family AuthServerData a :: *
42--
41--
43-- NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE
42-- NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE
44newtype AuthHandler r usr = AuthHandler
43newtype AuthHandler r usr = AuthHandler
45− { unAuthHandler :: r -> ExceptT ServantErr IO usr }
44+ { unAuthHandler :: r -> Handler usr }
46 deriving (Generic, Typeable)
45 deriving (Generic, Typeable)
47
46
48-- | NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE
47-- | NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE
49−mkAuthHandler :: (r -> ExceptT ServantErr IO usr) -> AuthHandler r usr
48+mkAuthHandler :: (r -> Handler usr) -> AuthHandler r usr
50mkAuthHandler = AuthHandler
49mkAuthHandler = AuthHandler
51
50
52-- | Known orphan instance.
51-- | Known orphan instance.
servant-server/src/Servant/Server/Internal.hs+9−10
@@ -22,7 +22,6 @@ module Servant.Server.Internal
22 , module Servant.Server.Internal.ServantErr
22 , module Servant.Server.Internal.ServantErr
23 ) where
23 ) where
24
24
25−import Control.Monad.Trans.Except (ExceptT)
26import qualified Data.ByteString as B
25import qualified Data.ByteString as B
27import qualified Data.ByteString.Char8 as BC8
26import qualified Data.ByteString.Char8 as BC8
28import qualified Data.ByteString.Lazy as BL
27import qualified Data.ByteString.Lazy as BL
@@ -73,7 +72,7 @@ class HasServer layout context where
73
72
74 route :: Proxy layout -> Context context -> Delayed (Server layout) -> Router
73 route :: Proxy layout -> Context context -> Delayed (Server layout) -> Router
75
74
76−type Server layout = ServerT layout (ExceptT ServantErr IO)
75+type Server layout = ServerT layout Handler
77
76
78-- * Instances
77-- * Instances
79
78
@@ -112,7 +111,7 @@ instance (HasServer a context, HasServer b context) => HasServer (a :<|> b) cont
112-- >
111-- >
113-- > server :: Server MyApi
112-- > server :: Server MyApi
114-- > server = getBook
113-- > server = getBook
115−-- > where getBook :: Text -> ExceptT ServantErr IO Book
114+-- > where getBook :: Text -> Handler Book
116-- > getBook isbn = ...
115-- > getBook isbn = ...
117instance (KnownSymbol capture, FromHttpApiData a, HasServer sublayout context)
116instance (KnownSymbol capture, FromHttpApiData a, HasServer sublayout context)
118 => HasServer (Capture capture a :> sublayout) context where
117 => HasServer (Capture capture a :> sublayout) context where
@@ -157,7 +156,7 @@ acceptCheck proxy accH
157
156
158methodRouter :: (AllCTRender ctypes a)
157methodRouter :: (AllCTRender ctypes a)
159 => Method -> Proxy ctypes -> Status
158 => Method -> Proxy ctypes -> Status
160− -> Delayed (ExceptT ServantErr IO a)
159+ -> Delayed (Handler a)
161 -> Router
160 -> Router
162methodRouter method proxy status action = leafRouter route'
161methodRouter method proxy status action = leafRouter route'
163 where
162 where
@@ -171,7 +170,7 @@ methodRouter method proxy status action = leafRouter route'
171
170
172methodRouterHeaders :: (GetHeaders (Headers h v), AllCTRender ctypes v)
171methodRouterHeaders :: (GetHeaders (Headers h v), AllCTRender ctypes v)
173 => Method -> Proxy ctypes -> Status
172 => Method -> Proxy ctypes -> Status
174− -> Delayed (ExceptT ServantErr IO (Headers h v))
173+ -> Delayed (Handler (Headers h v))
175 -> Router
174 -> Router
176methodRouterHeaders method proxy status action = leafRouter route'
175methodRouterHeaders method proxy status action = leafRouter route'
177 where
176 where
@@ -223,7 +222,7 @@ instance OVERLAPPING_
223-- >
222-- >
224-- > server :: Server MyApi
223-- > server :: Server MyApi
225-- > server = viewReferer
224-- > server = viewReferer
226−-- > where viewReferer :: Referer -> ExceptT ServantErr IO referer
225+-- > where viewReferer :: Referer -> Handler referer
227-- > viewReferer referer = return referer
226-- > viewReferer referer = return referer
228instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
227instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
229 => HasServer (Header sym a :> sublayout) context where
228 => HasServer (Header sym a :> sublayout) context where
@@ -254,7 +253,7 @@ instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
254-- >
253-- >
255-- > server :: Server MyApi
254-- > server :: Server MyApi
256-- > server = getBooksBy
255-- > server = getBooksBy
257−-- > where getBooksBy :: Maybe Text -> ExceptT ServantErr IO [Book]
256+-- > where getBooksBy :: Maybe Text -> Handler [Book]
258-- > getBooksBy Nothing = ...return all books...
257-- > getBooksBy Nothing = ...return all books...
259-- > getBooksBy (Just author) = ...return books by the given author...
258-- > getBooksBy (Just author) = ...return books by the given author...
260instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
259instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
@@ -291,7 +290,7 @@ instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
291-- >
290-- >
292-- > server :: Server MyApi
291-- > server :: Server MyApi
293-- > server = getBooksBy
292-- > server = getBooksBy
294−-- > where getBooksBy :: [Text] -> ExceptT ServantErr IO [Book]
293+-- > where getBooksBy :: [Text] -> Handler [Book]
295-- > getBooksBy authors = ...return all books by these authors...
294-- > getBooksBy authors = ...return all books by these authors...
296instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
295instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
297 => HasServer (QueryParams sym a :> sublayout) context where
296 => HasServer (QueryParams sym a :> sublayout) context where
@@ -322,7 +321,7 @@ instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
322-- >
321-- >
323-- > server :: Server MyApi
322-- > server :: Server MyApi
324-- > server = getBooks
323-- > server = getBooks
325−-- > where getBooks :: Bool -> ExceptT ServantErr IO [Book]
324+-- > where getBooks :: Bool -> Handler [Book]
326-- > getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument...
325-- > getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument...
327instance (KnownSymbol sym, HasServer sublayout context)
326instance (KnownSymbol sym, HasServer sublayout context)
328 => HasServer (QueryFlag sym :> sublayout) context where
327 => HasServer (QueryFlag sym :> sublayout) context where
@@ -379,7 +378,7 @@ instance HasServer Raw context where
379-- >
378-- >
380-- > server :: Server MyApi
379-- > server :: Server MyApi
381-- > server = postBook
380-- > server = postBook
382−-- > where postBook :: Book -> ExceptT ServantErr IO Book
381+-- > where postBook :: Book -> Handler Book
383-- > postBook book = ...insert into your db...
382-- > postBook book = ...insert into your db...
384instance ( AllCTUnrender list a, HasServer sublayout context
383instance ( AllCTUnrender list a, HasServer sublayout context
385 ) => HasServer (ReqBody list a :> sublayout) context where
384 ) => HasServer (ReqBody list a :> sublayout) context where
servant-server/src/Servant/Server/Internal/RoutingApplication.hs+2−2
@@ -8,7 +8,7 @@
8{-# LANGUAGE StandaloneDeriving #-}
8{-# LANGUAGE StandaloneDeriving #-}
9module Servant.Server.Internal.RoutingApplication where
9module Servant.Server.Internal.RoutingApplication where
10
10
11−import Control.Monad.Trans.Except (ExceptT, runExceptT)
11+import Control.Monad.Trans.Except (runExceptT)
12import Network.Wai (Application, Request,
12import Network.Wai (Application, Request,
13 Response, ResponseReceived)
13 Response, ResponseReceived)
14import Prelude ()
14import Prelude ()
@@ -222,7 +222,7 @@ runDelayed Delayed{..} =
222-- Takes a continuation that lets us send a response.
222-- Takes a continuation that lets us send a response.
223-- Also takes a continuation for how to turn the
223-- Also takes a continuation for how to turn the
224-- result of the delayed server into a response.
224-- result of the delayed server into a response.
225−runAction :: Delayed (ExceptT ServantErr IO a)
225+runAction :: Delayed (Handler a)
226 -> (RouteResult Response -> IO r)
226 -> (RouteResult Response -> IO r)
227 -> (a -> RouteResult Response)
227 -> (a -> RouteResult Response)
228 -> IO r
228 -> IO r
servant-server/src/Servant/Server/Internal/ServantErr.hs+33−30
@@ -4,6 +4,7 @@
4module Servant.Server.Internal.ServantErr where
4module Servant.Server.Internal.ServantErr where
5
5
6import Control.Exception (Exception)
6import Control.Exception (Exception)
7+import Control.Monad.Trans.Except (ExceptT)
7import qualified Data.ByteString.Char8 as BS
8import qualified Data.ByteString.Char8 as BS
8import qualified Data.ByteString.Lazy as LBS
9import qualified Data.ByteString.Lazy as LBS
9import Data.Typeable (Typeable)
10import Data.Typeable (Typeable)
@@ -18,6 +19,8 @@ data ServantErr = ServantErr { errHTTPCode :: Int
18
19
19instance Exception ServantErr
20instance Exception ServantErr
20
21
22+type Handler = ExceptT ServantErr IO
23+
21responseServantErr :: ServantErr -> Response
24responseServantErr :: ServantErr -> Response
22responseServantErr ServantErr{..} = responseLBS status errHeaders errBody
25responseServantErr ServantErr{..} = responseLBS status errHeaders errBody
23 where
26 where
@@ -27,7 +30,7 @@ responseServantErr ServantErr{..} = responseLBS status errHeaders errBody
27--
30--
28-- Example:
31-- Example:
29--
32--
30−-- > failingHandler :: ExceptT ServantErr IO ()
33+-- > failingHandler :: Handler ()
31-- > failingHandler = throwErr $ err300 { errBody = "I can't choose." }
34-- > failingHandler = throwErr $ err300 { errBody = "I can't choose." }
32--
35--
33err300 :: ServantErr
36err300 :: ServantErr
@@ -41,7 +44,7 @@ err300 = ServantErr { errHTTPCode = 300
41--
44--
42-- Example:
45-- Example:
43--
46--
44−-- > failingHandler :: ExceptT ServantErr IO ()
47+-- > failingHandler :: Handler ()
45-- > failingHandler = throwErr err301
48-- > failingHandler = throwErr err301
46--
49--
47err301 :: ServantErr
50err301 :: ServantErr
@@ -55,7 +58,7 @@ err301 = ServantErr { errHTTPCode = 301
55--
58--
56-- Example:
59-- Example:
57--
60--
58−-- > failingHandler :: ExceptT ServantErr IO ()
61+-- > failingHandler :: Handler ()
59-- > failingHandler = throwErr err302
62-- > failingHandler = throwErr err302
60--
63--
61err302 :: ServantErr
64err302 :: ServantErr
@@ -69,7 +72,7 @@ err302 = ServantErr { errHTTPCode = 302
69--
72--
70-- Example:
73-- Example:
71--
74--
72−-- > failingHandler :: ExceptT ServantErr IO ()
75+-- > failingHandler :: Handler ()
73-- > failingHandler = throwErr err303
76-- > failingHandler = throwErr err303
74--
77--
75err303 :: ServantErr
78err303 :: ServantErr
@@ -83,7 +86,7 @@ err303 = ServantErr { errHTTPCode = 303
83--
86--
84-- Example:
87-- Example:
85--
88--
86−-- > failingHandler :: ExceptT ServantErr IO ()
89+-- > failingHandler :: Handler ()
87-- > failingHandler = throwErr err304
90-- > failingHandler = throwErr err304
88--
91--
89err304 :: ServantErr
92err304 :: ServantErr
@@ -97,7 +100,7 @@ err304 = ServantErr { errHTTPCode = 304
97--
100--
98-- Example:
101-- Example:
99--
102--
100−-- > failingHandler :: ExceptT ServantErr IO ()
103+-- > failingHandler :: Handler ()
101-- > failingHandler = throwErr err305
104-- > failingHandler = throwErr err305
102--
105--
103err305 :: ServantErr
106err305 :: ServantErr
@@ -111,7 +114,7 @@ err305 = ServantErr { errHTTPCode = 305
111--
114--
112-- Example:
115-- Example:
113--
116--
114−-- > failingHandler :: ExceptT ServantErr IO ()
117+-- > failingHandler :: Handler ()
115-- > failingHandler = throwErr err307
118-- > failingHandler = throwErr err307
116--
119--
117err307 :: ServantErr
120err307 :: ServantErr
@@ -125,7 +128,7 @@ err307 = ServantErr { errHTTPCode = 307
125--
128--
126-- Example:
129-- Example:
127--
130--
128−-- > failingHandler :: ExceptT ServantErr IO ()
131+-- > failingHandler :: Handler ()
129-- > failingHandler = throwErr $ err400 { errBody = "Your request makes no sense to me." }
132-- > failingHandler = throwErr $ err400 { errBody = "Your request makes no sense to me." }
130--
133--
131err400 :: ServantErr
134err400 :: ServantErr
@@ -139,7 +142,7 @@ err400 = ServantErr { errHTTPCode = 400
139--
142--
140-- Example:
143-- Example:
141--
144--
142−-- > failingHandler :: ExceptT ServantErr IO ()
145+-- > failingHandler :: Handler ()
143-- > failingHandler = throwErr $ err401 { errBody = "Your credentials are invalid." }
146-- > failingHandler = throwErr $ err401 { errBody = "Your credentials are invalid." }
144--
147--
145err401 :: ServantErr
148err401 :: ServantErr
@@ -153,7 +156,7 @@ err401 = ServantErr { errHTTPCode = 401
153--
156--
154-- Example:
157-- Example:
155--
158--
156−-- > failingHandler :: ExceptT ServantErr IO ()
159+-- > failingHandler :: Handler ()
157-- > failingHandler = throwErr $ err402 { errBody = "You have 0 credits. Please give me $$$." }
160-- > failingHandler = throwErr $ err402 { errBody = "You have 0 credits. Please give me $$$." }
158--
161--
159err402 :: ServantErr
162err402 :: ServantErr
@@ -167,7 +170,7 @@ err402 = ServantErr { errHTTPCode = 402
167--
170--
168-- Example:
171-- Example:
169--
172--
170−-- > failingHandler :: ExceptT ServantErr IO ()
173+-- > failingHandler :: Handler ()
171-- > failingHandler = throwErr $ err403 { errBody = "Please login first." }
174-- > failingHandler = throwErr $ err403 { errBody = "Please login first." }
172--
175--
173err403 :: ServantErr
176err403 :: ServantErr
@@ -181,7 +184,7 @@ err403 = ServantErr { errHTTPCode = 403
181--
184--
182-- Example:
185-- Example:
183--
186--
184−-- > failingHandler :: ExceptT ServantErr IO ()
187+-- > failingHandler :: Handler ()
185-- > failingHandler = throwErr $ err404 { errBody = "(╯°□°)╯︵ ┻━┻)." }
188-- > failingHandler = throwErr $ err404 { errBody = "(╯°□°)╯︵ ┻━┻)." }
186--
189--
187err404 :: ServantErr
190err404 :: ServantErr
@@ -195,7 +198,7 @@ err404 = ServantErr { errHTTPCode = 404
195--
198--
196-- Example:
199-- Example:
197--
200--
198−-- > failingHandler :: ExceptT ServantErr IO ()
201+-- > failingHandler :: Handler ()
199-- > failingHandler = throwErr $ err405 { errBody = "Your account privileges does not allow for this. Please pay $$$." }
202-- > failingHandler = throwErr $ err405 { errBody = "Your account privileges does not allow for this. Please pay $$$." }
200--
203--
201err405 :: ServantErr
204err405 :: ServantErr
@@ -209,7 +212,7 @@ err405 = ServantErr { errHTTPCode = 405
209--
212--
210-- Example:
213-- Example:
211--
214--
212−-- > failingHandler :: ExceptT ServantErr IO ()
215+-- > failingHandler :: Handler ()
213-- > failingHandler = throwErr err406
216-- > failingHandler = throwErr err406
214--
217--
215err406 :: ServantErr
218err406 :: ServantErr
@@ -223,7 +226,7 @@ err406 = ServantErr { errHTTPCode = 406
223--
226--
224-- Example:
227-- Example:
225--
228--
226−-- > failingHandler :: ExceptT ServantErr IO ()
229+-- > failingHandler :: Handler ()
227-- > failingHandler = throwErr err407
230-- > failingHandler = throwErr err407
228--
231--
229err407 :: ServantErr
232err407 :: ServantErr
@@ -237,7 +240,7 @@ err407 = ServantErr { errHTTPCode = 407
237--
240--
238-- Example:
241-- Example:
239--
242--
240−-- > failingHandler :: ExceptT ServantErr IO ()
243+-- > failingHandler :: Handler ()
241-- > failingHandler = throwErr $ err409 { errBody = "Transaction conflicts with 59879cb56c7c159231eeacdd503d755f7e835f74" }
244-- > failingHandler = throwErr $ err409 { errBody = "Transaction conflicts with 59879cb56c7c159231eeacdd503d755f7e835f74" }
242--
245--
243err409 :: ServantErr
246err409 :: ServantErr
@@ -251,7 +254,7 @@ err409 = ServantErr { errHTTPCode = 409
251--
254--
252-- Example:
255-- Example:
253--
256--
254−-- > failingHandler :: ExceptT ServantErr IO ()
257+-- > failingHandler :: Handler ()
255-- > failingHandler = throwErr $ err410 { errBody = "I know it was here at some point, but.. I blame bad luck." }
258-- > failingHandler = throwErr $ err410 { errBody = "I know it was here at some point, but.. I blame bad luck." }
256--
259--
257err410 :: ServantErr
260err410 :: ServantErr
@@ -265,7 +268,7 @@ err410 = ServantErr { errHTTPCode = 410
265--
268--
266-- Example:
269-- Example:
267--
270--
268−-- > failingHandler :: ExceptT ServantErr IO ()
271+-- > failingHandler :: Handler ()
269-- > failingHandler = throwErr err411
272-- > failingHandler = throwErr err411
270--
273--
271err411 :: ServantErr
274err411 :: ServantErr
@@ -279,7 +282,7 @@ err411 = ServantErr { errHTTPCode = 411
279--
282--
280-- Example:
283-- Example:
281--
284--
282−-- > failingHandler :: ExceptT ServantErr IO ()
285+-- > failingHandler :: Handler ()
283-- > failingHandler = throwErr $ err412 { errBody = "Precondition fail: x < 42 && y > 57" }
286-- > failingHandler = throwErr $ err412 { errBody = "Precondition fail: x < 42 && y > 57" }
284--
287--
285err412 :: ServantErr
288err412 :: ServantErr
@@ -293,7 +296,7 @@ err412 = ServantErr { errHTTPCode = 412
293--
296--
294-- Example:
297-- Example:
295--
298--
296−-- > failingHandler :: ExceptT ServantErr IO ()
299+-- > failingHandler :: Handler ()
297-- > failingHandler = throwErr $ err413 { errBody = "Request exceeded 64k." }
300-- > failingHandler = throwErr $ err413 { errBody = "Request exceeded 64k." }
298--
301--
299err413 :: ServantErr
302err413 :: ServantErr
@@ -307,7 +310,7 @@ err413 = ServantErr { errHTTPCode = 413
307--
310--
308-- Example:
311-- Example:
309--
312--
310−-- > failingHandler :: ExceptT ServantErr IO ()
313+-- > failingHandler :: Handler ()
311-- > failingHandler = throwErr $ err414 { errBody = "Maximum length is 64." }
314-- > failingHandler = throwErr $ err414 { errBody = "Maximum length is 64." }
312--
315--
313err414 :: ServantErr
316err414 :: ServantErr
@@ -321,7 +324,7 @@ err414 = ServantErr { errHTTPCode = 414
321--
324--
322-- Example:
325-- Example:
323--
326--
324−-- > failingHandler :: ExceptT ServantErr IO ()
327+-- > failingHandler :: Handler ()
325-- > failingHandler = throwErr $ err415 { errBody = "Supported media types: gif, png" }
328-- > failingHandler = throwErr $ err415 { errBody = "Supported media types: gif, png" }
326--
329--
327err415 :: ServantErr
330err415 :: ServantErr
@@ -335,7 +338,7 @@ err415 = ServantErr { errHTTPCode = 415
335--
338--
336-- Example:
339-- Example:
337--
340--
338−-- > failingHandler :: ExceptT ServantErr IO ()
341+-- > failingHandler :: Handler ()
339-- > failingHandler = throwErr $ err416 { errBody = "Valid range is [0, 424242]." }
342-- > failingHandler = throwErr $ err416 { errBody = "Valid range is [0, 424242]." }
340--
343--
341err416 :: ServantErr
344err416 :: ServantErr
@@ -349,7 +352,7 @@ err416 = ServantErr { errHTTPCode = 416
349--
352--
350-- Example:
353-- Example:
351--
354--
352−-- > failingHandler :: ExceptT ServantErr IO ()
355+-- > failingHandler :: Handler ()
353-- > failingHandler = throwErr $ err417 { errBody = "I found a quux in the request. This isn't going to work." }
356-- > failingHandler = throwErr $ err417 { errBody = "I found a quux in the request. This isn't going to work." }
354--
357--
355err417 :: ServantErr
358err417 :: ServantErr
@@ -363,7 +366,7 @@ err417 = ServantErr { errHTTPCode = 417
363--
366--
364-- Example:
367-- Example:
365--
368--
366−-- > failingHandler :: ExceptT ServantErr IO ()
369+-- > failingHandler :: Handler ()
367-- > failingHandler = throwErr $ err500 { errBody = "Exception in module A.B.C:55. Have a great day!" }
370-- > failingHandler = throwErr $ err500 { errBody = "Exception in module A.B.C:55. Have a great day!" }
368--
371--
369err500 :: ServantErr
372err500 :: ServantErr
@@ -377,7 +380,7 @@ err500 = ServantErr { errHTTPCode = 500
377--
380--
378-- Example:
381-- Example:
379--
382--
380−-- > failingHandler :: ExceptT ServantErr IO ()
383+-- > failingHandler :: Handler ()
381-- > failingHandler = throwErr $ err501 { errBody = "/v1/foo is not supported with quux in the request." }
384-- > failingHandler = throwErr $ err501 { errBody = "/v1/foo is not supported with quux in the request." }
382--
385--
383err501 :: ServantErr
386err501 :: ServantErr
@@ -391,7 +394,7 @@ err501 = ServantErr { errHTTPCode = 501
391--
394--
392-- Example:
395-- Example:
393--
396--
394−-- > failingHandler :: ExceptT ServantErr IO ()
397+-- > failingHandler :: Handler ()
395-- > failingHandler = throwErr $ err502 { errBody = "Tried gateway foo, bar, and baz. None responded." }
398-- > failingHandler = throwErr $ err502 { errBody = "Tried gateway foo, bar, and baz. None responded." }
396--
399--
397err502 :: ServantErr
400err502 :: ServantErr
@@ -405,7 +408,7 @@ err502 = ServantErr { errHTTPCode = 502
405--
408--
406-- Example:
409-- Example:
407--
410--
408−-- > failingHandler :: ExceptT ServantErr IO ()
411+-- > failingHandler :: Handler ()
409-- > failingHandler = throwErr $ err503 { errBody = "We're rewriting in PHP." }
412-- > failingHandler = throwErr $ err503 { errBody = "We're rewriting in PHP." }
410--
413--
411err503 :: ServantErr
414err503 :: ServantErr
@@ -419,7 +422,7 @@ err503 = ServantErr { errHTTPCode = 503
419--
422--
420-- Example:
423-- Example:
421--
424--
422−-- > failingHandler :: ExceptT ServantErr IO ()
425+-- > failingHandler :: Handler ()
423-- > failingHandler = throwErr $ err504 { errBody = "Backend foobar did not respond in 5 seconds." }
426-- > failingHandler = throwErr $ err504 { errBody = "Backend foobar did not respond in 5 seconds." }
424--
427--
425err504 :: ServantErr
428err504 :: ServantErr
@@ -433,7 +436,7 @@ err504 = ServantErr { errHTTPCode = 504
433--
436--
434-- Example usage:
437-- Example usage:
435--
438--
436−-- > failingHandler :: ExceptT ServantErr IO ()
439+-- > failingHandler :: Handler ()
437-- > failingHandler = throwErr $ err505 { errBody = "I support HTTP/4.0 only." }
440-- > failingHandler = throwErr $ err505 { errBody = "I support HTTP/4.0 only." }
438--
441--
439err505 :: ServantErr
442err505 :: ServantErr
servant-server/test/Servant/Server/Internal/EnterSpec.hs+1−1
@@ -34,7 +34,7 @@ combinedAPI = Proxy
34readerServer' :: ServerT ReaderAPI (Reader String)
34readerServer' :: ServerT ReaderAPI (Reader String)
35readerServer' = return 1797 :<|> ask
35readerServer' = return 1797 :<|> ask
36
36
37−fReader :: Reader String :~> ExceptT ServantErr IO
37+fReader :: Reader String :~> Handler
38fReader = generalizeNat C.. (runReaderTNat "hi")
38fReader = generalizeNat C.. (runReaderTNat "hi")
39
39
40readerServer :: Server ReaderAPI
40readerServer :: Server ReaderAPI
servant-server/test/Servant/Server/StreamingSpec.hs+2−2
@@ -9,7 +9,7 @@
9module Servant.Server.StreamingSpec where
9module Servant.Server.StreamingSpec where
10
10
11import Control.Concurrent
11import Control.Concurrent
12−import Control.Exception
12+import Control.Exception hiding (Handler)
13import Control.Monad.IO.Class
13import Control.Monad.IO.Class
14import Control.Monad.Trans.Except
14import Control.Monad.Trans.Except
15import qualified Data.ByteString as Strict
15import qualified Data.ByteString as Strict
@@ -66,7 +66,7 @@ spec = do
66 -- - receives the first chunk
66 -- - receives the first chunk
67 -- - notifies serverReceivedFirstChunk
67 -- - notifies serverReceivedFirstChunk
68 -- - receives the rest of the request
68 -- - receives the rest of the request
69− let handler :: Lazy.ByteString -> ExceptT ServantErr IO NoContent
69+ let handler :: Lazy.ByteString -> Handler NoContent
70 handler input = liftIO $ do
70 handler input = liftIO $ do
71 let prefix = Lazy.take 3 input
71 let prefix = Lazy.take 3 input
72 prefix `shouldBe` "foo"
72 prefix `shouldBe` "foo"
servant-server/test/Servant/Server/UsingContextSpec.hs+1−1
@@ -25,7 +25,7 @@ spec = do
25type OneEntryAPI =
25type OneEntryAPI =
26 ExtractFromContext :> Get '[JSON] String
26 ExtractFromContext :> Get '[JSON] String
27
27
28−testServer :: String -> ExceptT ServantErr IO String
28+testServer :: String -> Handler String
29testServer s = return s
29testServer s = return s
30
30
31oneEntryApp :: Application
31oneEntryApp :: Application
servant-server/test/Servant/ServerSpec.hs+7−6
@@ -14,7 +14,7 @@
14module Servant.ServerSpec where
14module Servant.ServerSpec where
15
15
16import Control.Monad (forM_, when, unless)
16import Control.Monad (forM_, when, unless)
17−import Control.Monad.Trans.Except (ExceptT, throwE)
17+import Control.Monad.Trans.Except (throwE)
18import Data.Aeson (FromJSON, ToJSON, decode', encode)
18import Data.Aeson (FromJSON, ToJSON, decode', encode)
19import qualified Data.ByteString.Base64 as Base64
19import qualified Data.ByteString.Base64 as Base64
20import Data.ByteString.Conversion ()
20import Data.ByteString.Conversion ()
@@ -48,8 +48,9 @@ import Servant.API ((:<|>) (..), (:>), AuthProtect,
48 Raw, RemoteHost, ReqBody,
48 Raw, RemoteHost, ReqBody,
49 StdMethod (..), Verb, addHeader)
49 StdMethod (..), Verb, addHeader)
50import Servant.API.Internal.Test.ComprehensiveAPI
50import Servant.API.Internal.Test.ComprehensiveAPI
51−import Servant.Server (ServantErr (..), Server, err401, err403, err404,
51+import Servant.Server (ServantErr (..), Server, Handler, err401, err403,
52+ err404, serve, serveWithContext,
52− serve, serveWithContext, Context((:.), EmptyContext))
53+ Context((:.), EmptyContext))
53import Test.Hspec (Spec, context, describe, it,
54import Test.Hspec (Spec, context, describe, it,
54 shouldBe, shouldContain)
55 shouldBe, shouldContain)
55import qualified Test.Hspec.Wai as THW
56import qualified Test.Hspec.Wai as THW
@@ -180,7 +181,7 @@ verbSpec = describe "Servant.API.Verb" $ do
180type CaptureApi = Capture "legs" Integer :> Get '[JSON] Animal
181type CaptureApi = Capture "legs" Integer :> Get '[JSON] Animal
181captureApi :: Proxy CaptureApi
182captureApi :: Proxy CaptureApi
182captureApi = Proxy
183captureApi = Proxy
183−captureServer :: Integer -> ExceptT ServantErr IO Animal
184+captureServer :: Integer -> Handler Animal
184captureServer legs = case legs of
185captureServer legs = case legs of
185 4 -> return jerry
186 4 -> return jerry
186 2 -> return tweety
187 2 -> return tweety
@@ -336,11 +337,11 @@ headerApi = Proxy
336headerSpec :: Spec
337headerSpec :: Spec
337headerSpec = describe "Servant.API.Header" $ do
338headerSpec = describe "Servant.API.Header" $ do
338
339
339− let expectsInt :: Maybe Int -> ExceptT ServantErr IO ()
340+ let expectsInt :: Maybe Int -> Handler ()
340 expectsInt (Just x) = when (x /= 5) $ error "Expected 5"
341 expectsInt (Just x) = when (x /= 5) $ error "Expected 5"
341 expectsInt Nothing = error "Expected an int"
342 expectsInt Nothing = error "Expected an int"
342
343
343− let expectsString :: Maybe String -> ExceptT ServantErr IO ()
344+ let expectsString :: Maybe String -> Handler ()
344 expectsString (Just x) = when (x /= "more from you") $ error "Expected more from you"
345 expectsString (Just x) = when (x /= "more from you") $ error "Expected more from you"
345 expectsString Nothing = error "Expected a string"
346 expectsString Nothing = error "Expected a string"
346
347