module Rest.Types.Error
( DataError (..)
, DomainReason (..)
, Status (..)
, fromEither
, toEither
, Reason_
, Reason (..)
, SomeReason (..)
, ToResponseCode (..)
) where
import Control.Applicative (Applicative (..))
import Control.Monad (ap)
import Data.Aeson hiding (Success)
import Data.Foldable (Foldable)
import Data.JSON.Schema (JSONSchema (..), gSchema)
import Data.Traversable (Traversable)
import Data.Typeable
import GHC.Generics
import Generics.Generic.Aeson
import Generics.XmlPickler (gxpickle)
import Text.XML.HXT.Arrow.Pickle
import Text.XML.HXT.Arrow.Pickle.Schema
import Text.XML.HXT.Arrow.Pickle.Xml
import qualified Data.JSON.Schema as JSONSchema
import Rest.Types.Void
data DataError
= ParseError String
| PrintError String
| MissingField String
| UnsupportedFormat String
deriving (Eq, Generic, Show)
newtype DomainReason a = DomainReason { reason :: a }
deriving (Eq, Generic, Functor, Foldable, Show, Traversable)
instance XmlPickler a => XmlPickler (DomainReason a) where
xpickle = xpWrap (DomainReason, reason) xpickle
instance ToJSON a => ToJSON (DomainReason a) where
toJSON (DomainReason e) = toJSON e
instance FromJSON a => FromJSON (DomainReason a) where
parseJSON = fmap DomainReason . parseJSON
instance JSONSchema a => JSONSchema (DomainReason a) where
schema = schema . fmap reason
data Status a b = Failure a | Success b
deriving (Eq, Show, Generic, Typeable, Functor, Foldable, Traversable)
instance (XmlPickler a, XmlPickler b) => XmlPickler (Status a b) where
xpickle = gxpickle
instance (ToJSON a, ToJSON b) => ToJSON (Status a b) where toJSON = gtoJson
instance (FromJSON a, FromJSON b) => FromJSON (Status a b) where parseJSON = gparseJson
instance (JSONSchema a, JSONSchema b) => JSONSchema (Status a b) where
schema = gSchema
fromEither :: Either a b -> Status a b
fromEither = either Failure Success
toEither :: Status a b -> Either a b
toEither (Success x) = Right x
toEither (Failure y) = Left y
type Reason_ = Reason Void
data Reason a
= UnsupportedRoute
| UnsupportedMethod
| UnsupportedVersion
| IdentError DataError
| HeaderError DataError
| ParamError DataError
| InputError DataError
| OutputError DataError
| NotFound
| NotAllowed
| AuthenticationFailed
| Busy
| Gone
| CustomReason (DomainReason a)
deriving (Eq, Generic, Show, Typeable, Functor, Foldable, Traversable)
instance Applicative Reason where
pure = return
(<*>) = ap
instance Monad Reason where
return a = CustomReason (DomainReason a)
r >>= f = case r of
CustomReason (DomainReason a) -> f a
UnsupportedRoute -> UnsupportedRoute
UnsupportedMethod -> UnsupportedMethod
UnsupportedVersion -> UnsupportedVersion
IdentError e -> IdentError e
HeaderError e -> HeaderError e
ParamError e -> ParamError e
InputError e -> InputError e
OutputError e -> OutputError e
NotFound -> NotFound
NotAllowed -> NotAllowed
AuthenticationFailed -> AuthenticationFailed
Busy -> Busy
Gone -> Gone
instance XmlPickler DataError where xpickle = gxpickle
instance XmlPickler e => XmlPickler (Reason e) where xpickle = gxpickle
instance ToJSON DataError where toJSON = gtoJson
instance FromJSON DataError where parseJSON = gparseJson
instance ToJSON e => ToJSON (Reason e) where toJSON = gtoJson
instance FromJSON e => FromJSON (Reason e) where parseJSON = gparseJson
instance JSONSchema DataError where schema = gSchema
instance JSONSchema e => JSONSchema (Reason e) where schema = gSchema
data SomeReason where
SomeReason :: (XmlPickler e, JSONSchema e, ToJSON e) => Reason e -> SomeReason
deriving instance Typeable SomeReason
instance XmlPickler SomeReason where
xpickle = PU
(\(SomeReason e) st -> appPickle xpickle e st)
(throwMsg "Cannot unpickle SomeReason.")
Any
instance ToJSON SomeReason where toJSON (SomeReason r) = toJSON r
instance JSONSchema SomeReason where
schema _ = JSONSchema.Any
class ToResponseCode a where
toResponseCode :: a -> Int
instance ToResponseCode Void where
toResponseCode = magic
instance ToResponseCode a => ToResponseCode (Reason a) where
toResponseCode e =
case e of
NotFound -> 404
UnsupportedRoute -> 404
UnsupportedMethod -> 405
UnsupportedVersion -> 404
NotAllowed -> 403
AuthenticationFailed -> 401
Busy -> 503
Gone -> 410
OutputError (UnsupportedFormat _) -> 406
InputError _ -> 400
OutputError _ -> 500
IdentError _ -> 400
HeaderError _ -> 400
ParamError _ -> 400
CustomReason (DomainReason a) -> toResponseCode a