{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} module Data.JsonRpc.Failure ( Failure (..), Error (..), ErrorStatus (..), toCode, fromCode, refineStatus, failure, makeError, serverError, methodError, emptyError, ) where import Prelude hiding (userError) import Control.Monad (MonadPlus, mplus, guard) import Data.Maybe (fromMaybe) import Data.Text (Text) import Data.Foldable (Foldable) import Data.Traversable (Traversable) import Data.JsonRpc.Id (Id) data Failure e = Failure { _jsonrpc :: !Text , _id :: !(Maybe Id) , _error :: !(Error e) } deriving (Eq, Show, Functor, Foldable, Traversable) data Error e = Error { _code :: !ErrorStatus , _message :: !Text , _data :: !(Maybe e) } deriving (Eq, Show, Functor, Foldable, Traversable) {- -- citation from http://www.jsonrpc.org/specification -- -- The error codes from and including -32768 to -32000 are reserved for pre-defined errors. -- Any code within this range, but not defined explicitly below is reserved for future use. -- The error codes are nearly the same as those suggested for XML-RPC at the following -- url: http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php -- -- code message meaning -- -32700 Parse error Invalid JSON was received by the server. -- An error occurred on the server while parsing the JSON text. -- -32600 Invalid Request The JSON sent is not a valid Request object. -- -32601 Method not found The method does not exist / is not available. -- -32602 Invalid params Invalid method parameter(s). -- -32603 Internal error Internal JSON-RPC error. -- -32000 to -32099 Server error Reserved for implementation-defined server-errors. -- The remainder of the space is available for application defined errors. -} data ErrorStatus = ParseError | InvalidRequest | MethodNotFound | InvalidParams | InternalError | ServerError !Integer | MethodError !Integer deriving (Eq, Show) failure :: Maybe Id -> ErrorStatus -> Maybe Text -> Maybe e -> Failure e failure mayId s mm = Failure "2.0" mayId . makeError s mm defaultMessage :: ErrorStatus -> Text defaultMessage = d where d ParseError = "Parse error" d InvalidRequest = "Invalid Request" d MethodNotFound = "Method not found" d InvalidParams = "Invalid params" d InternalError = "Internal error" d (ServerError _) = "Server error" d (MethodError _) = "Application method error" toCode :: ErrorStatus -> Integer toCode = d where d ParseError = -32700 d InvalidRequest = -32600 d MethodNotFound = -32601 d InvalidParams = -32602 d InternalError = -32603 d (ServerError c) = c d (MethodError c) = c fromCode :: (Integral a, MonadPlus m) => a -> m ErrorStatus fromCode c' | c == -32700 = return ParseError | c == -32600 = return InvalidRequest | c == -32601 = return MethodNotFound | c == -32602 = return InvalidParams | c == -32603 = return InternalError | otherwise = serverError c `mplus` methodError c where c = toInteger c' refineStatus :: MonadPlus m => ErrorStatus -> m ErrorStatus refineStatus e = do e' <- fromCode $ toCode e guard $ e' == e return e makeError :: ErrorStatus -> Maybe Text -> Maybe e -> Error e makeError e = Error e . fromMaybe (defaultMessage e) serverError :: (Integral a, MonadPlus m) => a -> m ErrorStatus serverError c' = do let c = fromIntegral c' guard $ -32099 <= c && c <= -32000 return $ ServerError c methodError :: (Integral a, MonadPlus m) => a -> m ErrorStatus methodError c' = do let c = fromIntegral c' guard $ c < -32768 || -32000 < c return $ MethodError c emptyError :: Maybe () emptyError = Nothing