-
Notifications
You must be signed in to change notification settings - Fork 631
[CO-325] API V1 Improvements - Part 1 #3372
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, thanks @KtorZ !
I have added only some remarks to be intended as a chance to see if we can do better, but none of the comments above are serious blockers 😉
accountSpecs :: WalletRef -> WalletClient IO -> Spec | ||
accountSpecs _ wc = | ||
describe "Accounts" $ do | ||
it "can retrieve only an accounts balance" $ do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor typo: "an account".
@@ -43,6 +41,11 @@ import Cardano.Wallet.API.Response.Sort.IxSet as SortBackend | |||
import Cardano.Wallet.API.V1.Errors | |||
(WalletError (JSONValidationFailed)) | |||
|
|||
import qualified Data.Aeson.Options as Serokell | |||
import qualified Data.Char as Char | |||
import qualified Formatting.Buildable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a cunning reason why these were moved here? Is there a new coding guideline which suggest we move all the qualified imports at the bottom?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a habit indeed, I usually do that when rebasing because it makes merge-conflicts easier to solve. Not sure we have any particular guidelines about this; I know it was suggested in the past but not clearly stated as the way to go.
@@ -37,4 +40,14 @@ type API | |||
:> "certificates" | |||
:> ReqBody '[ValidJSON] Redemption | |||
:> Post '[ValidJSON] (WalletResponse Transaction) | |||
:<|> "wallets" :> CaptureWalletId :> "accounts" | |||
:> CaptureAccountId :> "addresses" | |||
:> Summary "Retrieve only account's addressees." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addresses ? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Referring to the typo addressees here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup 😃
-> FilterOperations WalletAddress | ||
-> Handler (WalletResponse AccountAddresses) | ||
getAccountAddresses _layer _wId _accIdx _pagination _filters = | ||
error "unimplemented" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we link to the ticket which is going to implement this?
Also, genuine question -- why not reuse a WalletResponse [WalletAddress]
, so we can do pagination the standard way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no such ticket yet 😶,about to create one.
why not reuse a WalletResponse [WalletAddress] , so we can do pagination the standard way?
Because of the way the input is returned. We made the choice of wrapping it inside a "partial" object with a single field { "addresses": [ ... ] }
to basically mimic the response you'd get when querying just an account. That's debatable, but that's what we've opted for, hence the wrapper.
-> AccountIndex | ||
-> Handler (WalletResponse AccountBalance) | ||
getAccountBalance _layer _wId _accIdx = | ||
error "unimplemented" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto as the above. Also, these two endpoints are more integration work for the new-wallet team (cc @edsko ).
Perhaps you folks could help with the integration work?
@@ -918,6 +925,15 @@ instance IxSet.Indexable (AccountIndex ': SecondaryAccountIxs) | |||
(OrdByPrimKey Account) where | |||
indices = ixList | |||
|
|||
-- | Datatype wrapping addresses for per-field endpoint | |||
newtype AccountAddresses = AccountAddresses | |||
{ acaAddresses :: [WalletAddress] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might be inclined to scrap this extra type if it was added only for "aesthetic" purposes to make the API description reads nicer and not for a real need. One less type to maintain 😉
@adinapoli-iohk Typos fixed & ticket created (and referred to) to track the implementation work for the partial getters in Accounts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
LGTM
addresses <- createAddresses wc 10 pair | ||
let addr = Prelude.head addresses | ||
let tests = | ||
[ PaginationTest (Just 1) (Just 5) NoFilters NoSorts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not use paginateAll
for tests like we did here https://github.com/input-output-hk/cardano-sl/pull/3372/files#diff-bff1c1799ab4f0868324f4083a4bd15aR251 (as we are not testing pagination in this specific spec)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to test pagination! Haha :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then it makes sense - hope we have specialized pagination tests somewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No we don't. We will soon.
@@ -94,12 +96,13 @@ initialWalletState wc = do | |||
_transactions = mempty | |||
_actionsNum = 0 | |||
_successActions = mempty | |||
pure $ WalletState {..} | |||
return WalletState {..} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its not important - but I wonder why return
instead of pure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! I guess it was irritating me. I like to use return
when inside a Monad
and pure
when inside an Applicative
. I know a Monad
is an Applicative
but well, just developer OCD I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we get the Monad of No Return you will be forced to adapt :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm with @KtorZ on this one! :)
bc3126a
to
b5e3d67
Compare
Aeson.encode (CBackupPhrase mnemonic) `shouldBe` jsonV0Compat bytes | ||
|
||
it "CBackupPhrase from JSON" $ forM_ testVectors $ \(bytes, _, mnemonic, _, _) -> | ||
it "CBackupPhrase from JSON" $ forM_ testVectors $ \(bytes, _, _, mnemonic, _, _) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure I understand this properly - but shouldn't this be called "CBackupPhrase from legacy JSON" as we are using jsonV0Compat
bellow?
This is new to me so I might have wrong understanding
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the naming here is in contrast to the next one, which is called "CBackupPhrase from legacy JSON".
The difference being bytes
vs legacyBytes
. Might exist better ways.
Aeson.decode (jsonV0Compat legacyBytes) `shouldBe` pure (CBackupPhrase mnemonic) | ||
|
||
it "Mnemonic from legacy JSON" $ forM_ testVectors $ \(_, legacyBytes, _, _, _, _) -> | ||
Aeson.decode legacyBytes `shouldSatisfy` isNothing @ (Mnemonic 12) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, I am probably missunderstanding it - but shouldn't it be Aeson.decode (jsonV0Compat legacyBytes)...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akegalj It should be correct, but it
description lacking, my bad.
So, examples:
bytes = ["word", "word", ...]
legacyBytes = ["word word word", "word", "word", ... ] -- could look like bytes too
(jsonV0Compat legacyBytes) = {"bpToList": ["word word word", "word", "word", ...]}
-- bytes is the format for Mnemonic
-- (jsonV0Compat legacyBytes) is the format for CBackupPhrase
This test makes sure that the Mnemonic
decoding doesn't work with legacyBytes.
I could
- Describe these concepts in a comment at the top of the file, near
TestVector
- Change the
it
description
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha it makes more sense now. Maybe having an example as you showed in the example above would be nice to have in comments. Nothing too serious though
I tested this together with #3367 and this solves the issues with creating and restoring wallets over api V0 |
-- "bpToList": ["squirrel material silly twice direct slush", | ||
-- "pistol razor", "becomed junk kingdom"] | ||
-- } | ||
-- as in addition to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a typo. "as" should be removed.
Now that client TLS verification is activated, clients are expected to provide a valid TLS client certificate. cURL command given as examples in the documentaiton should reflect that.
…rl-options-in-api-doc [CO-328] Add missing '--client' option in cURL API doc examples
Ideally, we want the /.../account/addresses to be paginated, otherwise there's no real value in isolating it as such. Also, for now, the implementation is rather heavy and requires the full account to be retrieved from the DB. On the long-term, we could imagine fetching only the addresses from the DB and streaming the response.
This is not 'ideal' yet because we are sorting and filtering on a plain list. Instead, we could have these operation at a DB-level, but this won't probably be achieved with acid-state. Perhaps if one day we switch to SQL
There was no integration tests for any accounts endpoints :s ... We should work on that in the future as I didn't take care of it in this commit / task, but solely add a few one for the newly added endpoints
Also, this rename the balance endpoint to '/api/v1/wallets/{id}/accounts/{ix}/amount' to reflect the actual name of the field in the Account representation.
1. Import and use `Example` typeclass in `../V1/Types.hs` instead of `Arbitrary` 2. Resolve circular dependencies `Errors.hs` -> `Types.hs` -> `Example.hs` -> `Response.hs` -> `Errors.hs` by moving `Example` instances from `Example.hs` to where the datatypes are defined, so that `Example.hs` does not need to import `Response.hs` or `Types.hs`.
…endpoints [CO-324] Accounts per-field endpoints
…e-typeclass [CO-327] Rely on Example type-class for Swagger API schema
As discussed here: https://github.com/input-output-hk/cardano-sl/pull/3210/files#r201989995, it doesn't make much sense to offer such capability right now as addresses are just a bunch of random characters (from the surface). Such feature could make sense with the new data-layer, but until then, we better disable it to prevent users from performing a costly operation
Weirdly, the conflict resolutions during rebase completely cut the end of some files in conflict. I was using a new tool for solving merge-conflict. Gotta be more careful
In order to maintain backwards compitability we also accept mnemonic words separated by spaces by `>>= (splitAt ' ')`
b5e3d67
to
e1d889d
Compare
Merging with failing AppVeyor (timeout). We ought to do something about it, almost impossible to get a PR green and it takes an unreasonable amount of time. |
Description
This PR contains some API V1 improvements. Another one will follow in the upcoming week with another set of changes. We are shipping this first part now to avoid too big PR and because some of its content is needed by the Daedalus team to move on.
This contains:
Linked issue
[CO-325]
Type of change
Developer checklist
Testing checklist
QA Steps
Screenshots (if available)