Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

309 handle application exceptions with 500 errors #954

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion servant-server/example/greet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
{-# LANGUAGE TypeOperators #-}

import Data.Aeson
import Data.Monoid
import Data.Proxy
import Data.Text
import GHC.Generics
Expand Down
1 change: 1 addition & 0 deletions servant-server/servant-server.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ library
build-depends:
base-compat >= 0.10.1 && < 0.11
, base64-bytestring >= 1.0.0.1 && < 1.1
, deepseq >= 1.4.3.0 && < 1.5
, exceptions >= 0.10.0 && < 0.11
, http-api-data >= 0.3.8.1 && < 0.4
, http-media >= 0.7.1.2 && < 0.8
Expand Down
2 changes: 1 addition & 1 deletion servant-server/src/Servant/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ serve p = serveWithContext p EmptyContext
serveWithContext :: (HasServer api context)
=> Proxy api -> Context context -> Server api -> Application
serveWithContext p context server =
toApplication (runRouter (route p context (emptyDelayed (Route server))))
toApplication True (runRouter (route p context (emptyDelayed (Route server))))

-- | Hoist server implementation.
--
Expand Down
23 changes: 16 additions & 7 deletions servant-server/src/Servant/Server/Internal/RoutingApplication.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
{-# LANGUAGE UndecidableInstances #-}
module Servant.Server.Internal.RoutingApplication where

import Control.DeepSeq
(force)
import Control.Monad
(ap, liftM)
import Control.Monad.Base
Expand Down Expand Up @@ -93,13 +95,20 @@ instance MonadTransControl RouteResultT where
instance MonadThrow m => MonadThrow (RouteResultT m) where
throwM = lift . throwM

toApplication :: RoutingApplication -> Application
toApplication ra request respond = ra request routingRespond
where
routingRespond :: RouteResult Response -> IO ResponseReceived
routingRespond (Fail err) = respond $ responseServantErr err
routingRespond (FailFatal err) = respond $ responseServantErr err
routingRespond (Route v) = respond v
toApplication :: Bool -> RoutingApplication -> Application
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last nitpick: let's have

data Evaluate = Force | Lazy deriving (Show)

so we won't be Bool-blind.

toApplication fullyEvaluate ra request respond =
ra request (maybeEval routingRespond)
where
maybeEval :: (RouteResult Response -> IO ResponseReceived)
-> RouteResult Response -> IO ResponseReceived
maybeEval resp =
if fullyEvaluate
then force resp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else resp
routingRespond :: RouteResult Response -> IO ResponseReceived
routingRespond (Fail err) = respond $ responseServantErr err
routingRespond (FailFatal err) = respond $ responseServantErr err
routingRespond (Route v) = respond v

-- | A 'Delayed' is a representation of a handler with scheduled
-- delayed checks that can trigger errors.
Expand Down
6 changes: 5 additions & 1 deletion servant-server/src/Servant/Server/Internal/ServantErr.hs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Servant.Server.Internal.ServantErr where

import Control.Exception
(Exception)
import Control.DeepSeq (NFData)
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy as LBS
import Data.Typeable
(Typeable)
import GHC.Generics (Generic)
import qualified Network.HTTP.Types as HTTP
import Network.Wai
(Response, responseLBS)
Expand All @@ -17,7 +21,7 @@ data ServantErr = ServantErr { errHTTPCode :: Int
, errReasonPhrase :: String
, errBody :: LBS.ByteString
, errHeaders :: [HTTP.Header]
} deriving (Show, Eq, Read, Typeable)
} deriving (Show, Eq, Read, Typeable, Generic, NFData)

instance Exception ServantErr

Expand Down