2015-05-02 04:38:53 +02:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
{-# LANGUAGE RecordWildCards #-}
|
2016-02-26 13:01:54 +01:00
|
|
|
{-# LANGUAGE DeriveDataTypeable #-}
|
2015-05-02 04:38:53 +02:00
|
|
|
module Servant.Server.Internal.ServantErr where
|
|
|
|
|
2016-02-26 12:27:19 +01:00
|
|
|
import Control.Exception (Exception)
|
2015-08-17 23:56:29 +02:00
|
|
|
import qualified Data.ByteString.Char8 as BS
|
|
|
|
import qualified Data.ByteString.Lazy as LBS
|
2016-02-26 12:27:19 +01:00
|
|
|
import Data.Typeable (Typeable)
|
2015-08-17 23:56:29 +02:00
|
|
|
import qualified Network.HTTP.Types as HTTP
|
|
|
|
import Network.Wai (Response, responseLBS)
|
2015-05-02 04:38:53 +02:00
|
|
|
|
|
|
|
data ServantErr = ServantErr { errHTTPCode :: Int
|
|
|
|
, errReasonPhrase :: String
|
|
|
|
, errBody :: LBS.ByteString
|
|
|
|
, errHeaders :: [HTTP.Header]
|
2016-02-26 12:27:19 +01:00
|
|
|
} deriving (Show, Eq, Read, Typeable)
|
|
|
|
|
|
|
|
instance Exception ServantErr
|
2015-05-02 04:38:53 +02:00
|
|
|
|
|
|
|
responseServantErr :: ServantErr -> Response
|
|
|
|
responseServantErr ServantErr{..} = responseLBS status errHeaders errBody
|
|
|
|
where
|
|
|
|
status = HTTP.mkStatus errHTTPCode (BS.pack errReasonPhrase)
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err300' Multiple Choices
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err300 { errBody = "I can't choose." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err300 :: ServantErr
|
|
|
|
err300 = ServantErr { errHTTPCode = 300
|
|
|
|
, errReasonPhrase = "Multiple Choices"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err301' Moved Permanently
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr err301
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err301 :: ServantErr
|
|
|
|
err301 = ServantErr { errHTTPCode = 301
|
|
|
|
, errReasonPhrase = "Moved Permanently"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err302' Found
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr err302
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err302 :: ServantErr
|
|
|
|
err302 = ServantErr { errHTTPCode = 302
|
|
|
|
, errReasonPhrase = "Found"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err303' See Other
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr err303
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err303 :: ServantErr
|
|
|
|
err303 = ServantErr { errHTTPCode = 303
|
|
|
|
, errReasonPhrase = "See Other"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err304' Not Modified
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr err304
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err304 :: ServantErr
|
|
|
|
err304 = ServantErr { errHTTPCode = 304
|
|
|
|
, errReasonPhrase = "Not Modified"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err305' Use Proxy
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr err305
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err305 :: ServantErr
|
|
|
|
err305 = ServantErr { errHTTPCode = 305
|
|
|
|
, errReasonPhrase = "Use Proxy"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err307' Temporary Redirect
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
2016-03-25 19:09:44 +01:00
|
|
|
-- > failingHandler = throwErr err307
|
2016-03-25 10:53:45 +01:00
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err307 :: ServantErr
|
|
|
|
err307 = ServantErr { errHTTPCode = 307
|
|
|
|
, errReasonPhrase = "Temporary Redirect"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err400' Bad Request
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err400 { errBody = "Your request makes no sense to me." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err400 :: ServantErr
|
|
|
|
err400 = ServantErr { errHTTPCode = 400
|
|
|
|
, errReasonPhrase = "Bad Request"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err401' Unauthorized
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err401 { errBody = "Your credentials are invalid." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err401 :: ServantErr
|
|
|
|
err401 = ServantErr { errHTTPCode = 401
|
|
|
|
, errReasonPhrase = "Unauthorized"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err402' Payment Required
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err402 { errBody = "You have 0 credits. Please give me $$$." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err402 :: ServantErr
|
|
|
|
err402 = ServantErr { errHTTPCode = 402
|
|
|
|
, errReasonPhrase = "Payment Required"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err403' Forbidden
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err403 { errBody = "Please login first." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err403 :: ServantErr
|
|
|
|
err403 = ServantErr { errHTTPCode = 403
|
|
|
|
, errReasonPhrase = "Forbidden"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err404' Not Found
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err404 { errBody = "(╯°□°)╯︵ ┻━┻)." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err404 :: ServantErr
|
|
|
|
err404 = ServantErr { errHTTPCode = 404
|
|
|
|
, errReasonPhrase = "Not Found"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err405' Method Not Allowed
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err405 { errBody = "Your account privileges does not allow for this. Please pay $$$." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err405 :: ServantErr
|
|
|
|
err405 = ServantErr { errHTTPCode = 405
|
|
|
|
, errReasonPhrase = "Method Not Allowed"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err406' Not Acceptable
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
2016-03-25 19:09:44 +01:00
|
|
|
-- > failingHandler = throwErr err406
|
2016-03-25 10:53:45 +01:00
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err406 :: ServantErr
|
|
|
|
err406 = ServantErr { errHTTPCode = 406
|
|
|
|
, errReasonPhrase = "Not Acceptable"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err407' Proxy Authentication Required
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
2016-03-25 19:09:44 +01:00
|
|
|
-- > failingHandler = throwErr err407
|
2016-03-25 10:53:45 +01:00
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err407 :: ServantErr
|
|
|
|
err407 = ServantErr { errHTTPCode = 407
|
|
|
|
, errReasonPhrase = "Proxy Authentication Required"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err409' Conflict
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err409 { errBody = "Transaction conflicts with 59879cb56c7c159231eeacdd503d755f7e835f74" }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err409 :: ServantErr
|
|
|
|
err409 = ServantErr { errHTTPCode = 409
|
|
|
|
, errReasonPhrase = "Conflict"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err410' Gone
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err410 { errBody = "I know it was here at some point, but.. I blame bad luck." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err410 :: ServantErr
|
|
|
|
err410 = ServantErr { errHTTPCode = 410
|
|
|
|
, errReasonPhrase = "Gone"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err411' Length Required
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
2016-03-25 19:09:44 +01:00
|
|
|
-- > failingHandler = throwErr err411
|
2016-03-25 10:53:45 +01:00
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err411 :: ServantErr
|
|
|
|
err411 = ServantErr { errHTTPCode = 411
|
|
|
|
, errReasonPhrase = "Length Required"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err412' Precondition Failed
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err412 { errBody = "Precondition fail: x < 42 && y > 57" }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err412 :: ServantErr
|
|
|
|
err412 = ServantErr { errHTTPCode = 412
|
|
|
|
, errReasonPhrase = "Precondition Failed"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err413' Request Entity Too Large
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err413 { errBody = "Request exceeded 64k." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err413 :: ServantErr
|
|
|
|
err413 = ServantErr { errHTTPCode = 413
|
|
|
|
, errReasonPhrase = "Request Entity Too Large"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err414' Request-URI Too Large
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
2016-03-25 19:09:44 +01:00
|
|
|
-- > failingHandler = throwErr $ err414 { errBody = "Maximum length is 64." }
|
2016-03-25 10:53:45 +01:00
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err414 :: ServantErr
|
|
|
|
err414 = ServantErr { errHTTPCode = 414
|
|
|
|
, errReasonPhrase = "Request-URI Too Large"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err415' Unsupported Media Type
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err415 { errBody = "Supported media types: gif, png" }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err415 :: ServantErr
|
|
|
|
err415 = ServantErr { errHTTPCode = 415
|
|
|
|
, errReasonPhrase = "Unsupported Media Type"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err416' Request range not satisfiable
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err416 { errBody = "Valid range is [0, 424242]." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err416 :: ServantErr
|
|
|
|
err416 = ServantErr { errHTTPCode = 416
|
|
|
|
, errReasonPhrase = "Request range not satisfiable"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err417' Expectation Failed
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err417 { errBody = "I found a quux in the request. This isn't going to work." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err417 :: ServantErr
|
|
|
|
err417 = ServantErr { errHTTPCode = 417
|
|
|
|
, errReasonPhrase = "Expectation Failed"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err500' Internal Server Error
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
2016-03-25 19:09:44 +01:00
|
|
|
-- > failingHandler = throwErr $ err500 { errBody = "Exception in module A.B.C:55. Have a great day!" }
|
2016-03-25 10:53:45 +01:00
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err500 :: ServantErr
|
|
|
|
err500 = ServantErr { errHTTPCode = 500
|
|
|
|
, errReasonPhrase = "Internal Server Error"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err501' Not Implemented
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err501 { errBody = "/v1/foo is not supported with quux in the request." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err501 :: ServantErr
|
|
|
|
err501 = ServantErr { errHTTPCode = 501
|
|
|
|
, errReasonPhrase = "Not Implemented"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err502' Bad Gateway
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err502 { errBody = "Tried gateway foo, bar, and baz. None responded." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err502 :: ServantErr
|
|
|
|
err502 = ServantErr { errHTTPCode = 502
|
|
|
|
, errReasonPhrase = "Bad Gateway"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err503' Service Unavailable
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err503 { errBody = "We're rewriting in PHP." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err503 :: ServantErr
|
|
|
|
err503 = ServantErr { errHTTPCode = 503
|
|
|
|
, errReasonPhrase = "Service Unavailable"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err504' Gateway Time-out
|
|
|
|
--
|
|
|
|
-- Example:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err504 { errBody = "Backend foobar did not respond in 5 seconds." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err504 :: ServantErr
|
|
|
|
err504 = ServantErr { errHTTPCode = 504
|
|
|
|
, errReasonPhrase = "Gateway Time-out"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|
|
|
|
|
2016-03-25 10:53:45 +01:00
|
|
|
-- | 'err505' HTTP Version not supported
|
|
|
|
--
|
|
|
|
-- Example usage:
|
|
|
|
--
|
|
|
|
-- > failingHandler :: ExceptT ServantErr IO ()
|
|
|
|
-- > failingHandler = throwErr $ err505 { errBody = "I support HTTP/4.0 only." }
|
|
|
|
--
|
2015-05-02 04:38:53 +02:00
|
|
|
err505 :: ServantErr
|
|
|
|
err505 = ServantErr { errHTTPCode = 505
|
|
|
|
, errReasonPhrase = "HTTP Version not supported"
|
|
|
|
, errBody = ""
|
|
|
|
, errHeaders = []
|
|
|
|
}
|