Skip to content

Commit 3a18d29

Browse files
committed
Remove unnecessary json parsing and refactor blockfrost errors
1 parent 46b6ff2 commit 3a18d29

File tree

1 file changed

+38
-29
lines changed

1 file changed

+38
-29
lines changed

src/Seabug/Metadata.purs

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
module Seabug.Metadata
2-
( FullSeabugMetadata
2+
( BlockfrostFetchError(..)
3+
, FullSeabugMetadata
34
, Hash
45
, getFullSeabugMetadata
56
) where
67

78
import Contract.Prelude
89

910
import Aeson as Aeson
11+
import Affjax (printError)
1012
import Affjax as Affjax
1113
import Affjax.RequestHeader as Affjax.RequestHeader
1214
import Affjax.ResponseFormat as Affjax.ResponseFormat
1315
import Cardano.Types.Value as Cardano.Types.Value
1416
import Contract.Prim.ByteArray (byteArrayToHex)
15-
import Contract.Transaction
16-
( ClientError(ClientHttpError, ClientDecodeJsonError)
17-
)
1817
import Contract.Value
1918
( CurrencySymbol
2019
, TokenName
@@ -23,12 +22,13 @@ import Contract.Value
2322
, mkCurrencySymbol
2423
)
2524
import Control.Alternative (guard)
25+
import Control.Monad.Error.Class (throwError)
2626
import Control.Monad.Except.Trans (ExceptT(ExceptT), except, runExceptT)
2727
import Control.Monad.Reader (ReaderT, runReaderT)
2828
import Control.Monad.Reader.Trans (asks)
2929
import Control.Monad.Trans.Class (lift)
3030
import Data.Argonaut as Argonaut
31-
import Data.Bifunctor (bimap, lmap)
31+
import Data.Bifunctor (lmap)
3232
import Data.Function (on)
3333
import Data.HTTP.Method (Method(GET))
3434
import Metadata.Seabug (SeabugMetadata(SeabugMetadata))
@@ -42,27 +42,35 @@ type FullSeabugMetadata =
4242
, ipfsHash :: Hash
4343
}
4444

45-
type BlockfrostFetch a = ExceptT ClientError
45+
data BlockfrostFetchError
46+
= BlockfrostRateLimit
47+
| BlockfrostOtherError String
48+
49+
derive instance Generic BlockfrostFetchError _
50+
51+
instance Show BlockfrostFetchError where
52+
show = genericShow
53+
54+
type BlockfrostFetch a = ExceptT BlockfrostFetchError
4655
(ReaderT { projectId :: String } Aff)
4756
a
4857

4958
getFullSeabugMetadata
5059
:: CurrencySymbol /\ TokenName
5160
-> String
52-
-> Aff (Either ClientError FullSeabugMetadata)
61+
-> Aff (Either BlockfrostFetchError FullSeabugMetadata)
5362
getFullSeabugMetadata a@(currSym /\ _) projectId =
5463
flip runReaderT { projectId } <<< runExceptT $ do
55-
seabugMetadata <- getMintingTxSeabugMetadata currSym =<<
56-
getMintingTxHash
57-
a
64+
seabugMetadata <-
65+
getMintingTxSeabugMetadata currSym =<< getMintingTxHash a
5866
ipfsHash <- getIpfsHash seabugMetadata
5967
pure { seabugMetadata, ipfsHash }
6068

6169
getIpfsHash
6270
:: SeabugMetadata
6371
-> BlockfrostFetch Hash
6472
getIpfsHash (SeabugMetadata { collectionNftCS, collectionNftTN }) = do
65-
except <<< (decodeField "image" <=< decodeFieldJson "onchain_metadata")
73+
except <<< (decodeField "image" <=< decodeField "onchain_metadata")
6674
=<< mkGetRequest ("assets/" <> mkAsset curr collectionNftTN)
6775
where
6876
curr :: CurrencySymbol
@@ -77,13 +85,13 @@ getMintingTxSeabugMetadata
7785
getMintingTxSeabugMetadata currSym txHash = do
7886
res <- mkGetRequest $ "txs/" <> txHash <> "/metadata"
7987
ms <- except
80-
$ lmap ClientDecodeJsonError
88+
$ lmap (BlockfrostOtherError <<< show)
8189
$ Aeson.caseAesonArray
8290
(Left (Argonaut.TypeMismatch "Expected array of objects"))
8391
Right
84-
(Aeson.jsonToAeson res)
92+
res
8593
except
86-
$ note (ClientDecodeJsonError (Argonaut.UnexpectedValue res))
94+
$ note (BlockfrostOtherError ("Unexpected JSON: " <> show res))
8795
$ findSeabugMetadata ms
8896
where
8997
findSeabugMetadata :: Array Aeson.Aeson -> Maybe SeabugMetadata
@@ -102,7 +110,7 @@ getMintingTxHash
102110
. CurrencySymbol /\ TokenName
103111
-> BlockfrostFetch Hash
104112
getMintingTxHash a =
105-
except <<< decodeFieldJson "initial_mint_tx_hash"
113+
except <<< decodeField "initial_mint_tx_hash"
106114
=<< mkGetRequest ("assets/" <> uncurry mkAsset a)
107115

108116
mkAsset :: CurrencySymbol -> TokenName -> String
@@ -115,40 +123,41 @@ decodeField
115123
. Aeson.DecodeAeson a
116124
=> String
117125
-> Aeson.Aeson
118-
-> Either ClientError a
126+
-> Either BlockfrostFetchError a
119127
decodeField field = do
120-
lmap ClientDecodeJsonError <<<
128+
lmap (BlockfrostOtherError <<< show) <<<
121129
( Aeson.decodeAeson
122130
<=< Aeson.caseAesonObject
123131
(Left (Argonaut.TypeMismatch "Expected Object"))
124132
(flip Aeson.getField field)
125133
)
126134

127-
decodeFieldJson
128-
:: forall (a :: Type)
129-
. Aeson.DecodeAeson a
130-
=> String
131-
-> Argonaut.Json
132-
-> Either ClientError a
133-
decodeFieldJson field = decodeField field <<< Aeson.jsonToAeson
134-
135135
mkGetRequest
136136
:: forall (r :: Row Type)
137137
. String
138-
-> BlockfrostFetch Argonaut.Json
138+
-> BlockfrostFetch Aeson.Aeson
139139
mkGetRequest path = do
140140
projectId <- lift $ asks $ _.projectId
141141
let
142-
req :: Affjax.Request Argonaut.Json
142+
req :: Affjax.Request String
143143
req = Affjax.defaultRequest
144144
{ url = mkUrl
145-
, responseFormat = Affjax.ResponseFormat.json
145+
, responseFormat = Affjax.ResponseFormat.string
146146
, method = Left GET
147147
, headers =
148148
[ Affjax.RequestHeader.RequestHeader "project_id" projectId
149149
]
150150
}
151-
ExceptT $ liftAff $ Affjax.request req <#> bimap ClientHttpError _.body
151+
res <- ExceptT $ liftAff $ do
152+
r <- Affjax.request req <#> lmap (BlockfrostOtherError <<< printError)
153+
case r of
154+
Left e -> log $ show e
155+
Right _ -> pure unit
156+
pure r
157+
when (unwrap res.status == 429) $ throwError $ BlockfrostRateLimit
158+
except $
159+
lmap (BlockfrostOtherError <<< (("Error parsing JSON: " <> _) <<< show))
160+
(Aeson.parseJsonStringToAeson res.body)
152161
where
153162
mkUrl :: String
154163
mkUrl = "https://cardano-testnet.blockfrost.io/api/v0/" <> path

0 commit comments

Comments
 (0)