Skip to content
This repository was archived by the owner on Aug 18, 2020. It is now read-only.

Commit e81cabe

Browse files
authored
Merge pull request #3429 from input-output-hk/Squad1/CBR-26/improve-error-handling
[CBR-26] Error Handling Improvements
2 parents 4246051 + e7f76f5 commit e81cabe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1042
-880
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,22 @@
1414

1515
[PR 3365]: https://github.com/input-output-hk/cardano-sl/pull/3365
1616

17+
- Improve type safety (and as a consequence, API documentation) of account indexes (CBR-306)
18+
1719
### Improvements
1820

21+
- Friendly error mistakes from deserializing invalid addresses instead of brutal 500 (CBR-283)
22+
23+
- **[API BREAKING CHANGE]** Add `walletId` to `WalletAlreadyExists` WalletLayerError (CBR-254)
24+
25+
- Small refactor of wallet Errors implementation to be more maintainable (CBR-26)
26+
1927
### Specifications
2028

2129
### Documentation
2230

31+
- Make an inventory of existing wallet errors and exceptions (CBR-307)
32+
2333

2434
## Cardano SL 1.3.0
2535

pkgs/default.nix

-2
Original file line numberDiff line numberDiff line change
@@ -17806,7 +17806,6 @@ license = stdenv.lib.licenses.mit;
1780617806
, http-client-tls
1780717807
, http-types
1780817808
, ixset-typed
17809-
, json-sop
1781017809
, lens
1781117810
, log-warper
1781217811
, memory
@@ -17912,7 +17911,6 @@ http-client
1791217911
http-client-tls
1791317912
http-types
1791417913
ixset-typed
17915-
json-sop
1791617914
lens
1791717915
log-warper
1791817916
memory

wallet-new/cardano-sl-wallet-new.cabal

+1-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ library
4444
Cardano.Wallet.API.V1.Handlers.Addresses
4545
Cardano.Wallet.API.V1.Handlers.Transactions
4646
Cardano.Wallet.API.V1.Handlers.Wallets
47+
Cardano.Wallet.API.V1.Headers
4748
Cardano.Wallet.API.V1.Info
4849
Cardano.Wallet.API.V1.LegacyHandlers
4950
Cardano.Wallet.API.V1.LegacyHandlers.Accounts
@@ -183,7 +184,6 @@ library
183184
, http-client-tls
184185
, http-types
185186
, ixset-typed
186-
, json-sop
187187
, lens
188188
, log-warper
189189
, memory
@@ -530,7 +530,6 @@ test-suite wallet-new-specs
530530
RequestSpec
531531
WalletHandlersSpec
532532
WalletNewJson
533-
WalletNewGen
534533
Cardano.Wallet.WalletLayer.QuickCheck
535534

536535
default-language: Haskell2010

wallet-new/integration/TransactionSpecs.hs

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ module TransactionSpecs (transactionSpecs) where
55

66
import Universum
77

8-
import Cardano.Wallet.API.V1.Errors hiding (describe)
98
import Cardano.Wallet.Client.Http
9+
import Control.Concurrent (threadDelay)
1010
import Control.Lens
11-
import qualified Pos.Core as Core
1211
import Test.Hspec
13-
14-
import Control.Concurrent (threadDelay)
1512
import Text.Show.Pretty (ppShow)
13+
14+
import qualified Pos.Core as Core
15+
1616
import Util
1717

1818
{-# ANN module ("HLint: ignore Reduce duplication" :: Text) #-}

wallet-new/integration/WalletSpecs.hs

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ module WalletSpecs (walletSpecs) where
55

66
import Universum
77

8-
import Cardano.Wallet.API.V1.Errors
9-
(WalletError (WalletAlreadyExists))
108
import Cardano.Wallet.Client.Http
119
import Control.Lens
1210
import Test.Hspec
@@ -63,8 +61,10 @@ walletSpecs _ wc = do
6361
}
6462
-- First wallet creation/restoration should succeed
6563
result <- postWallet wc newWallet1
66-
void $ result `shouldPrism` _Right
64+
wallet <- fmap wrData (result `shouldPrism` _Right)
6765
-- Second wallet creation/restoration should rise WalletAlreadyExists
6866
eresp <- postWallet wc newWallet2
6967
clientError <- eresp `shouldPrism` _Left
70-
clientError `shouldBe` ClientWalletError WalletAlreadyExists
68+
clientError
69+
`shouldBe`
70+
ClientWalletError (WalletAlreadyExists (walId wallet))

wallet-new/src/Cardano/Wallet/API/Response.hs

+54-12
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
{-# LANGUAGE DeriveFunctor #-}
22
{-# LANGUAGE DeriveGeneric #-}
3+
{-# LANGUAGE LambdaCase #-}
34
{-# LANGUAGE OverloadedLists #-}
45
module Cardano.Wallet.API.Response (
56
Metadata (..)
67
, ResponseStatus(..)
78
, WalletResponse(..)
9+
, JSONValidationError(..)
810
-- * Generating responses for collections
911
, respondWith
1012
, fromSlice
@@ -18,18 +20,22 @@ module Cardano.Wallet.API.Response (
1820
) where
1921

2022
import Prelude
21-
import Universum (Buildable, decodeUtf8, toText, (<>))
23+
import Universum (Buildable, Exception, Text, decodeUtf8, toText,
24+
(<>))
2225

23-
import Cardano.Wallet.API.Response.JSend (ResponseStatus (..))
24-
import Cardano.Wallet.API.V1.Swagger.Example (Example, example)
2526
import Control.Lens
26-
import Data.Aeson
27+
import Data.Aeson (FromJSON (..), ToJSON (..), eitherDecode, encode)
2728
import Data.Aeson.Encode.Pretty (encodePretty)
29+
import qualified Data.Aeson.Options as Serokell
2830
import Data.Aeson.TH
31+
import qualified Data.Char as Char
2932
import Data.Swagger as S hiding (Example, example)
3033
import Data.Typeable
3134
import Formatting (bprint, build, (%))
35+
import qualified Formatting.Buildable
36+
import Generics.SOP.TH (deriveGeneric)
3237
import GHC.Generics (Generic)
38+
import Servant (err400)
3339
import Servant.API.ContentTypes (Accept (..), JSON, MimeRender (..),
3440
MimeUnrender (..), OctetStream)
3541
import Test.QuickCheck
@@ -42,14 +48,13 @@ import Cardano.Wallet.API.Request.Pagination (Page (..),
4248
PerPage (..))
4349
import Cardano.Wallet.API.Request.Sort (SortOperations (..))
4450
import Cardano.Wallet.API.Response.Filter.IxSet as FilterBackend
51+
import Cardano.Wallet.API.Response.JSend (HasDiagnostic (..),
52+
ResponseStatus (..))
4553
import Cardano.Wallet.API.Response.Sort.IxSet as SortBackend
46-
import Cardano.Wallet.API.V1.Errors
47-
(WalletError (JSONValidationFailed))
48-
49-
import qualified Data.Aeson.Options as Serokell
50-
import qualified Data.Char as Char
51-
import qualified Formatting.Buildable
52-
54+
import Cardano.Wallet.API.V1.Errors (ToServantError (..))
55+
import Cardano.Wallet.API.V1.Generic (jsendErrorGenericParseJSON,
56+
jsendErrorGenericToJSON)
57+
import Cardano.Wallet.API.V1.Swagger.Example (Example, example)
5358

5459
-- | Extra information associated with an HTTP response.
5560
data Metadata = Metadata
@@ -166,7 +171,7 @@ respondWith :: (Monad m, Indexable' a)
166171
-> m (WalletResponse [a])
167172
respondWith RequestParams{..} fops sorts generator = do
168173
(theData, paginationMetadata) <- paginate rpPaginationParams . sortData sorts . applyFilters fops <$> generator
169-
return $ WalletResponse {
174+
return WalletResponse {
170175
wrData = theData
171176
, wrStatus = SuccessStatus
172177
, wrMeta = Metadata paginationMetadata
@@ -225,3 +230,40 @@ instance Accept ValidJSON where
225230

226231
instance ToJSON a => MimeRender ValidJSON a where
227232
mimeRender _ = mimeRender (Proxy @ JSON)
233+
234+
235+
--
236+
-- Error from parsing / validating JSON inputs
237+
--
238+
239+
newtype JSONValidationError
240+
= JSONValidationFailed Text
241+
deriving (Eq, Show, Generic)
242+
243+
deriveGeneric ''JSONValidationError
244+
245+
instance ToJSON JSONValidationError where
246+
toJSON =
247+
jsendErrorGenericToJSON
248+
249+
instance FromJSON JSONValidationError where
250+
parseJSON =
251+
jsendErrorGenericParseJSON
252+
253+
instance Exception JSONValidationError
254+
255+
instance Arbitrary JSONValidationError where
256+
arbitrary =
257+
pure (JSONValidationFailed "JSON validation failed.")
258+
259+
instance Buildable JSONValidationError where
260+
build _ =
261+
bprint "Couldn't decode a JSON input."
262+
263+
instance HasDiagnostic JSONValidationError where
264+
getDiagnosticKey _ =
265+
"validationError"
266+
267+
instance ToServantError JSONValidationError where
268+
declareServantError _ =
269+
err400

wallet-new/src/Cardano/Wallet/API/Response/JSend.hs

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ data ResponseStatus =
1717

1818
deriveJSON defaultOptions { Data.Aeson.TH.constructorTagModifier = map Char.toLower . reverse . drop 6 . reverse } ''ResponseStatus
1919

20+
class HasDiagnostic a where
21+
getDiagnosticKey :: a -> Text
22+
23+
noDiagnosticKey :: Text
24+
noDiagnosticKey =
25+
error "Contructor has declared no diagnostic key but apparently requires one! Have a look at HasDiagnostic instances!"
26+
2027
instance Arbitrary ResponseStatus where
2128
arbitrary = elements [minBound .. maxBound]
2229

0 commit comments

Comments
 (0)