diff --git a/api/accounts.go b/api/accounts.go index 7de92ac00..fe0a76f18 100644 --- a/api/accounts.go +++ b/api/accounts.go @@ -367,7 +367,16 @@ func (a *API) accountElectionsListByPageHandler(_ *apirest.APIdata, ctx *httprou return ErrMissingParameter } - return a.sendElectionList(ctx, params) + list, err := a.electionList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyElectionsList()) + } + return err + } + + return marshalAndSend(ctx, list) } // accountElectionsListByStatusAndPageHandler @@ -398,7 +407,16 @@ func (a *API) accountElectionsListByStatusAndPageHandler(_ *apirest.APIdata, ctx return ErrMissingParameter } - return a.sendElectionList(ctx, params) + list, err := a.electionList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyElectionsList()) + } + return err + } + + return marshalAndSend(ctx, list) } // accountElectionsCountHandler @@ -458,7 +476,16 @@ func (a *API) tokenTransfersListHandler(_ *apirest.APIdata, ctx *httprouter.HTTP return err } - return a.sendTransfersList(ctx, params) + list, err := a.transfersList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyTransfersList()) + } + return err + } + + return marshalAndSend(ctx, list) } // tokenFeesHandler @@ -490,7 +517,16 @@ func (a *API) tokenFeesHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) return ErrMissingParameter } - return a.sendFeesList(ctx, params) + list, err := a.feesList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyFeesList()) + } + return err + } + + return marshalAndSend(ctx, list) } // tokenTransfersCountHandler @@ -546,7 +582,17 @@ func (a *API) accountListByPageHandler(_ *apirest.APIdata, ctx *httprouter.HTTPC if err != nil { return err } - return a.sendAccountList(ctx, params) + + list, err := a.accountList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyAccountsList()) + } + return err + } + + return marshalAndSend(ctx, list) } // accountListHandler @@ -570,33 +616,38 @@ func (a *API) accountListHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext if err != nil { return err } - return a.sendAccountList(ctx, params) + + list, err := a.accountList(params) + if err != nil { + return err + } + + return marshalAndSend(ctx, list) } -// sendAccountList produces a paginated AccountsList, -// and sends it marshalled over ctx.Send +// accountList produces a paginated AccountsList. // // Errors returned are always of type APIerror. -func (a *API) sendAccountList(ctx *httprouter.HTTPContext, params *AccountParams) error { +func (a *API) accountList(params *AccountParams) (*AccountsList, error) { accounts, total, err := a.indexer.AccountList( params.Limit, params.Page*params.Limit, params.AccountID, ) if err != nil { - return ErrIndexerQueryFailed.WithErr(err) + return nil, ErrIndexerQueryFailed.WithErr(err) } pagination, err := calculatePagination(params.Page, params.Limit, total) if err != nil { - return err + return nil, err } list := &AccountsList{ Accounts: accounts, Pagination: pagination, } - return marshalAndSend(ctx, list) + return list, nil } // parseAccountParams returns an AccountParams filled with the passed params diff --git a/api/chain.go b/api/chain.go index 85c88801c..ed35bbad1 100644 --- a/api/chain.go +++ b/api/chain.go @@ -267,7 +267,13 @@ func (a *API) organizationListHandler(_ *apirest.APIdata, ctx *httprouter.HTTPCo if err != nil { return err } - return a.sendOrganizationList(ctx, params) + + list, err := a.organizationList(params) + if err != nil { + return err + } + + return marshalAndSend(ctx, list) } // organizationListByPageHandler @@ -291,7 +297,17 @@ func (a *API) organizationListByPageHandler(_ *apirest.APIdata, ctx *httprouter. if err != nil { return err } - return a.sendOrganizationList(ctx, params) + + list, err := a.organizationList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyOrganizationsList()) + } + return err + } + + return marshalAndSend(ctx, list) } // organizationListByFilterAndPageHandler @@ -325,26 +341,34 @@ func (a *API) organizationListByFilterAndPageHandler(msg *apirest.APIdata, ctx * return ErrMissingParameter } - return a.sendOrganizationList(ctx, params) + list, err := a.organizationList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyOrganizationsList()) + } + return err + } + + return marshalAndSend(ctx, list) } -// sendOrganizationList produces a filtered, paginated OrganizationsList, -// and sends it marshalled over ctx.Send +// organizationList produces a filtered, paginated OrganizationsList. // // Errors returned are always of type APIerror. -func (a *API) sendOrganizationList(ctx *httprouter.HTTPContext, params *OrganizationParams) error { +func (a *API) organizationList(params *OrganizationParams) (*OrganizationsList, error) { orgs, total, err := a.indexer.EntityList( params.Limit, params.Page*params.Limit, params.OrganizationID, ) if err != nil { - return ErrIndexerQueryFailed.WithErr(err) + return nil, ErrIndexerQueryFailed.WithErr(err) } pagination, err := calculatePagination(params.Page, params.Limit, total) if err != nil { - return err + return nil, err } list := &OrganizationsList{ @@ -357,7 +381,7 @@ func (a *API) sendOrganizationList(ctx *httprouter.HTTPContext, params *Organiza ElectionCount: uint64(org.ProcessCount), }) } - return marshalAndSend(ctx, list) + return list, nil } // organizationCountHandler @@ -738,7 +762,12 @@ func (a *API) chainTxListHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext return err } - return a.sendTransactionList(ctx, params) + list, err := a.transactionList(params) + if err != nil { + return err + } + + return marshalAndSend(ctx, list) } // chainTxListByPageHandler @@ -764,7 +793,16 @@ func (a *API) chainTxListByPageHandler(_ *apirest.APIdata, ctx *httprouter.HTTPC return err } - return a.sendTransactionList(ctx, params) + list, err := a.transactionList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyTransactionsList()) + } + return err + } + + return marshalAndSend(ctx, list) } // chainTxListByHeightAndPageHandler @@ -791,14 +829,22 @@ func (a *API) chainTxListByHeightAndPageHandler(_ *apirest.APIdata, ctx *httprou return err } - return a.sendTransactionList(ctx, params) + list, err := a.transactionList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyTransactionsList()) + } + return err + } + + return marshalAndSend(ctx, list) } -// sendTransactionList produces a filtered, paginated TransactionList, -// and sends it marshalled over ctx.Send +// transactionList produces a filtered, paginated TransactionList. // // Errors returned are always of type APIerror. -func (a *API) sendTransactionList(ctx *httprouter.HTTPContext, params *TransactionParams) error { +func (a *API) transactionList(params *TransactionParams) (*TransactionsList, error) { txs, total, err := a.indexer.SearchTransactions( params.Limit, params.Page*params.Limit, @@ -806,19 +852,19 @@ func (a *API) sendTransactionList(ctx *httprouter.HTTPContext, params *Transacti params.Type, ) if err != nil { - return ErrIndexerQueryFailed.WithErr(err) + return nil, ErrIndexerQueryFailed.WithErr(err) } pagination, err := calculatePagination(params.Page, params.Limit, total) if err != nil { - return err + return nil, err } list := &TransactionsList{ Transactions: txs, Pagination: pagination, } - return marshalAndSend(ctx, list) + return list, nil } // chainValidatorsHandler @@ -971,7 +1017,12 @@ func (a *API) chainFeesListHandler(_ *apirest.APIdata, ctx *httprouter.HTTPConte return err } - return a.sendFeesList(ctx, params) + list, err := a.feesList(params) + if err != nil { + return err + } + + return marshalAndSend(ctx, list) } // chainFeesListByPageHandler @@ -998,7 +1049,16 @@ func (a *API) chainFeesListByPageHandler(_ *apirest.APIdata, ctx *httprouter.HTT return err } - return a.sendFeesList(ctx, params) + list, err := a.feesList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyFeesList()) + } + return err + } + + return marshalAndSend(ctx, list) } // chainFeesListByReferenceAndPageHandler @@ -1030,7 +1090,16 @@ func (a *API) chainFeesListByReferenceAndPageHandler(_ *apirest.APIdata, ctx *ht return ErrMissingParameter } - return a.sendFeesList(ctx, params) + list, err := a.feesList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyFeesList()) + } + return err + } + + return marshalAndSend(ctx, list) } // chainFeesListByTypeAndPageHandler @@ -1062,16 +1131,24 @@ func (a *API) chainFeesListByTypeAndPageHandler(_ *apirest.APIdata, ctx *httprou return ErrMissingParameter } - return a.sendFeesList(ctx, params) + list, err := a.feesList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyFeesList()) + } + return err + } + + return marshalAndSend(ctx, list) } -// sendFeesList produces a filtered, paginated FeesList, -// and sends it marshalled over ctx.Send +// feesList produces a filtered, paginated FeesList. // // Errors returned are always of type APIerror. -func (a *API) sendFeesList(ctx *httprouter.HTTPContext, params *FeesParams) error { +func (a *API) feesList(params *FeesParams) (*FeesList, error) { if params.AccountID != "" && !a.indexer.AccountExists(params.AccountID) { - return ErrAccountNotFound + return nil, ErrAccountNotFound } fees, total, err := a.indexer.TokenFeesList( @@ -1082,19 +1159,19 @@ func (a *API) sendFeesList(ctx *httprouter.HTTPContext, params *FeesParams) erro params.AccountID, ) if err != nil { - return ErrIndexerQueryFailed.WithErr(err) + return nil, ErrIndexerQueryFailed.WithErr(err) } pagination, err := calculatePagination(params.Page, params.Limit, total) if err != nil { - return err + return nil, err } list := &FeesList{ Fees: fees, Pagination: pagination, } - return marshalAndSend(ctx, list) + return list, nil } // chainTransfersListHandler @@ -1123,17 +1200,21 @@ func (a *API) chainTransfersListHandler(_ *apirest.APIdata, ctx *httprouter.HTTP return err } - return a.sendTransfersList(ctx, params) + list, err := a.transfersList(params) + if err != nil { + return err + } + + return marshalAndSend(ctx, list) } -// sendTransfersList produces a filtered, paginated TokenTransfersList, -// and sends it marshalled over ctx.Send +// transfersList produces a filtered, paginated TransfersList. // // Errors returned are always of type APIerror. -func (a *API) sendTransfersList(ctx *httprouter.HTTPContext, params *TransfersParams) error { +func (a *API) transfersList(params *TransfersParams) (*TransfersList, error) { for _, param := range []string{params.AccountID, params.AccountIDFrom, params.AccountIDTo} { if param != "" && !a.indexer.AccountExists(param) { - return ErrAccountNotFound.With(param) + return nil, ErrAccountNotFound.With(param) } } @@ -1145,19 +1226,19 @@ func (a *API) sendTransfersList(ctx *httprouter.HTTPContext, params *TransfersPa params.AccountIDTo, ) if err != nil { - return ErrIndexerQueryFailed.WithErr(err) + return nil, ErrIndexerQueryFailed.WithErr(err) } pagination, err := calculatePagination(params.Page, params.Limit, total) if err != nil { - return err + return nil, err } list := &TransfersList{ Transfers: transfers, Pagination: pagination, } - return marshalAndSend(ctx, list) + return list, nil } // chainIndexerExportHandler diff --git a/api/elections.go b/api/elections.go index 89b4d7411..9e921f616 100644 --- a/api/elections.go +++ b/api/elections.go @@ -169,7 +169,16 @@ func (a *API) electionListByFilterAndPageHandler(msg *apirest.APIdata, ctx *http return ErrMissingParameter } - return a.sendElectionList(ctx, params) + list, err := a.electionList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyElectionsList()) + } + return err + } + + return marshalAndSend(ctx, list) } // electionListByFilterHandler @@ -191,7 +200,16 @@ func (a *API) electionListByFilterHandler(msg *apirest.APIdata, ctx *httprouter. return ErrCantParseDataAsJSON.WithErr(err) } - return a.sendElectionList(ctx, params) + list, err := a.electionList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyElectionsList()) + } + return err + } + + return marshalAndSend(ctx, list) } // electionListByPageHandler @@ -213,7 +231,17 @@ func (a *API) electionListByPageHandler(_ *apirest.APIdata, ctx *httprouter.HTTP if err != nil { return err } - return a.sendElectionList(ctx, params) + + list, err := a.electionList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyElectionsList()) + } + return err + } + + return marshalAndSend(ctx, list) } // electionListHandler @@ -251,21 +279,26 @@ func (a *API) electionListHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContex if err != nil { return err } - return a.sendElectionList(ctx, params) + + list, err := a.electionList(params) + if err != nil { + return err + } + + return marshalAndSend(ctx, list) } -// sendElectionList produces a filtered, paginated ElectionsList, -// and sends it marshalled over ctx.Send +// electionList produces a filtered, paginated ElectionsList. // // Errors returned are always of type APIerror. -func (a *API) sendElectionList(ctx *httprouter.HTTPContext, params *ElectionParams) error { +func (a *API) electionList(params *ElectionParams) (*ElectionsList, error) { if params.OrganizationID != "" && !a.indexer.EntityExists(params.OrganizationID) { - return ErrOrgNotFound + return nil, ErrOrgNotFound } status, err := parseStatus(params.Status) if err != nil { - return err + return nil, err } eids, total, err := a.indexer.ProcessList( @@ -285,12 +318,12 @@ func (a *API) sendElectionList(ctx *httprouter.HTTPContext, params *ElectionPara params.EndDateBefore, ) if err != nil { - return ErrIndexerQueryFailed.WithErr(err) + return nil, ErrIndexerQueryFailed.WithErr(err) } pagination, err := calculatePagination(params.Page, params.Limit, total) if err != nil { - return err + return nil, err } list := &ElectionsList{ @@ -300,11 +333,11 @@ func (a *API) sendElectionList(ctx *httprouter.HTTPContext, params *ElectionPara for _, eid := range eids { e, err := a.indexer.ProcessInfo(eid) if err != nil { - return ErrCantFetchElection.Withf("(%x): %v", eid, err) + return nil, ErrCantFetchElection.Withf("(%x): %v", eid, err) } list.Elections = append(list.Elections, a.electionSummary(e)) } - return marshalAndSend(ctx, list) + return list, nil } // electionHandler @@ -483,7 +516,17 @@ func (a *API) electionVotesListByPageHandler(_ *apirest.APIdata, ctx *httprouter if err != nil { return err } - return a.sendVotesList(ctx, params) + + list, err := a.votesList(params) + if err != nil { + // keep legacy behaviour of sending an empty list rather than a 404 + if errors.Is(err, ErrPageNotFound) { + return marshalAndSend(ctx, emptyVotesList()) + } + return err + } + + return marshalAndSend(ctx, list) } // electionScrutinyHandler diff --git a/api/legacy.go b/api/legacy.go new file mode 100644 index 000000000..436ea1531 --- /dev/null +++ b/api/legacy.go @@ -0,0 +1,61 @@ +package api + +// +// Legacy lists used to return an empty list (instead of null or an error) +// + +func emptyElectionsList() any { + return struct { + List []any `json:"elections"` + }{ + List: []any{}, + } +} + +func emptyOrganizationsList() any { + return struct { + List []any `json:"organizations"` + }{ + List: []any{}, + } +} + +func emptyVotesList() any { + return struct { + List []any `json:"votes"` + }{ + List: []any{}, + } +} + +func emptyTransactionsList() any { + return struct { + List []any `json:"transactions"` + }{ + List: []any{}, + } +} + +func emptyFeesList() any { + return struct { + List []any `json:"fees"` + }{ + List: []any{}, + } +} + +func emptyTransfersList() any { + return struct { + List []any `json:"transfers"` + }{ + List: []any{}, + } +} + +func emptyAccountsList() any { + return struct { + List []any `json:"accounts"` + }{ + List: []any{}, + } +} diff --git a/api/vote.go b/api/vote.go index 33322b103..aeda3a862 100644 --- a/api/vote.go +++ b/api/vote.go @@ -218,16 +218,21 @@ func (a *API) votesListHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) if err != nil { return err } - return a.sendVotesList(ctx, params) + + list, err := a.votesList(params) + if err != nil { + return err + } + + return marshalAndSend(ctx, list) } -// sendVotesList produces a filtered, paginated VotesList, -// and sends it marshalled over ctx.Send +// votesList produces a filtered, paginated VotesList. // // Errors returned are always of type APIerror. -func (a *API) sendVotesList(ctx *httprouter.HTTPContext, params *VoteParams) error { +func (a *API) votesList(params *VoteParams) (*VotesList, error) { if params.ElectionID != "" && !a.indexer.ProcessExists(params.ElectionID) { - return ErrElectionNotFound + return nil, ErrElectionNotFound } votes, total, err := a.indexer.VoteList( @@ -237,12 +242,12 @@ func (a *API) sendVotesList(ctx *httprouter.HTTPContext, params *VoteParams) err "", ) if err != nil { - return ErrIndexerQueryFailed.WithErr(err) + return nil, ErrIndexerQueryFailed.WithErr(err) } pagination, err := calculatePagination(params.Page, params.Limit, total) if err != nil { - return err + return nil, err } list := &VotesList{ @@ -259,7 +264,7 @@ func (a *API) sendVotesList(ctx *httprouter.HTTPContext, params *VoteParams) err TransactionIndex: &vote.TxIndex, }) } - return marshalAndSend(ctx, list) + return list, nil } // parseVoteParams returns an VoteParams filled with the passed params