mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-07 06:36:46 +00:00
[NOD-398] Change API server type HandlerError to work with errors instead of error strings (#454)
* [NOD-398] Change API server type HandlerError to work with errors instead of error strings * [NOD-398] Rename OriginalError -> Cause and isHandleError -> ok
This commit is contained in:
parent
3cc6f2d648
commit
a9ff9b0e70
@ -2,10 +2,10 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"github.com/daglabs/btcd/apiserver/apimodels"
|
"github.com/daglabs/btcd/apiserver/apimodels"
|
||||||
"github.com/daglabs/btcd/apiserver/dbmodels"
|
"github.com/daglabs/btcd/apiserver/dbmodels"
|
||||||
"github.com/daglabs/btcd/httpserverutils"
|
"github.com/daglabs/btcd/httpserverutils"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/daglabs/btcd/apiserver/database"
|
"github.com/daglabs/btcd/apiserver/database"
|
||||||
@ -27,38 +27,38 @@ const (
|
|||||||
const maxGetBlocksLimit = 100
|
const maxGetBlocksLimit = 100
|
||||||
|
|
||||||
// GetBlockByHashHandler returns a block by a given hash.
|
// GetBlockByHashHandler returns a block by a given hash.
|
||||||
func GetBlockByHashHandler(blockHash string) (interface{}, *httpserverutils.HandlerError) {
|
func GetBlockByHashHandler(blockHash string) (interface{}, error) {
|
||||||
if bytes, err := hex.DecodeString(blockHash); err != nil || len(bytes) != daghash.HashSize {
|
if bytes, err := hex.DecodeString(blockHash); err != nil || len(bytes) != daghash.HashSize {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity,
|
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity,
|
||||||
fmt.Sprintf("The given block hash is not a hex-encoded %d-byte hash.", daghash.HashSize))
|
errors.Errorf("The given block hash is not a hex-encoded %d-byte hash.", daghash.HashSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := database.DB()
|
db, err := database.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewInternalServerHandlerError(err.Error())
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
block := &dbmodels.Block{}
|
block := &dbmodels.Block{}
|
||||||
dbResult := db.Where(&dbmodels.Block{BlockHash: blockHash}).Preload("AcceptingBlock").First(block)
|
dbResult := db.Where(&dbmodels.Block{BlockHash: blockHash}).Preload("AcceptingBlock").First(block)
|
||||||
dbErrors := dbResult.GetErrors()
|
dbErrors := dbResult.GetErrors()
|
||||||
if httpserverutils.IsDBRecordNotFoundError(dbErrors) {
|
if httpserverutils.IsDBRecordNotFoundError(dbErrors) {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusNotFound, "No block with the given block hash was found.")
|
return nil, httpserverutils.NewHandlerError(http.StatusNotFound, errors.New("No block with the given block hash was found"))
|
||||||
}
|
}
|
||||||
if httpserverutils.HasDBError(dbErrors) {
|
if httpserverutils.HasDBError(dbErrors) {
|
||||||
return nil, httpserverutils.NewHandlerErrorFromDBErrors("Some errors were encountered when loading transactions from the database:", dbResult.GetErrors())
|
return nil, httpserverutils.NewErrorFromDBErrors("Some errors were encountered when loading transactions from the database:", dbResult.GetErrors())
|
||||||
}
|
}
|
||||||
return convertBlockModelToBlockResponse(block), nil
|
return convertBlockModelToBlockResponse(block), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlocksHandler searches for all blocks
|
// GetBlocksHandler searches for all blocks
|
||||||
func GetBlocksHandler(order string, skip uint64, limit uint64) (interface{}, *httpserverutils.HandlerError) {
|
func GetBlocksHandler(order string, skip uint64, limit uint64) (interface{}, error) {
|
||||||
if limit > maxGetBlocksLimit {
|
if limit > maxGetBlocksLimit {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity, fmt.Sprintf("The maximum allowed value for the limit is %d", maxGetTransactionsLimit))
|
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity, errors.Errorf("The maximum allowed value for the limit is %d", maxGetTransactionsLimit))
|
||||||
}
|
}
|
||||||
blocks := []*dbmodels.Block{}
|
blocks := []*dbmodels.Block{}
|
||||||
db, err := database.DB()
|
db, err := database.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
return nil, err
|
||||||
}
|
}
|
||||||
query := db.
|
query := db.
|
||||||
Limit(limit).
|
Limit(limit).
|
||||||
@ -69,7 +69,7 @@ func GetBlocksHandler(order string, skip uint64, limit uint64) (interface{}, *ht
|
|||||||
} else if order == OrderDescending {
|
} else if order == OrderDescending {
|
||||||
query = query.Order("`id` DESC")
|
query = query.Order("`id` DESC")
|
||||||
} else {
|
} else {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity, fmt.Sprintf("'%s' is not a valid order", order))
|
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity, errors.Errorf("'%s' is not a valid order", order))
|
||||||
}
|
}
|
||||||
query.Find(&blocks)
|
query.Find(&blocks)
|
||||||
blockResponses := make([]*apimodels.BlockResponse, len(blocks))
|
blockResponses := make([]*apimodels.BlockResponse, len(blocks))
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/daglabs/btcd/blockdag"
|
"github.com/daglabs/btcd/blockdag"
|
||||||
"github.com/daglabs/btcd/httpserverutils"
|
"github.com/daglabs/btcd/httpserverutils"
|
||||||
"github.com/daglabs/btcd/util/subnetworkid"
|
"github.com/daglabs/btcd/util/subnetworkid"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/daglabs/btcd/apiserver/database"
|
"github.com/daglabs/btcd/apiserver/database"
|
||||||
@ -23,15 +24,15 @@ import (
|
|||||||
const maxGetTransactionsLimit = 1000
|
const maxGetTransactionsLimit = 1000
|
||||||
|
|
||||||
// GetTransactionByIDHandler returns a transaction by a given transaction ID.
|
// GetTransactionByIDHandler returns a transaction by a given transaction ID.
|
||||||
func GetTransactionByIDHandler(txID string) (interface{}, *httpserverutils.HandlerError) {
|
func GetTransactionByIDHandler(txID string) (interface{}, error) {
|
||||||
if bytes, err := hex.DecodeString(txID); err != nil || len(bytes) != daghash.TxIDSize {
|
if bytes, err := hex.DecodeString(txID); err != nil || len(bytes) != daghash.TxIDSize {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity,
|
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity,
|
||||||
fmt.Sprintf("The given txid is not a hex-encoded %d-byte hash.", daghash.TxIDSize))
|
errors.Errorf("The given txid is not a hex-encoded %d-byte hash.", daghash.TxIDSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := database.DB()
|
db, err := database.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewInternalServerHandlerError(err.Error())
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tx := &dbmodels.Transaction{}
|
tx := &dbmodels.Transaction{}
|
||||||
@ -39,24 +40,24 @@ func GetTransactionByIDHandler(txID string) (interface{}, *httpserverutils.Handl
|
|||||||
dbResult := addTxPreloadedFields(query).First(&tx)
|
dbResult := addTxPreloadedFields(query).First(&tx)
|
||||||
dbErrors := dbResult.GetErrors()
|
dbErrors := dbResult.GetErrors()
|
||||||
if httpserverutils.IsDBRecordNotFoundError(dbErrors) {
|
if httpserverutils.IsDBRecordNotFoundError(dbErrors) {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusNotFound, "No transaction with the given txid was found.")
|
return nil, httpserverutils.NewHandlerError(http.StatusNotFound, errors.New("No transaction with the given txid was found"))
|
||||||
}
|
}
|
||||||
if httpserverutils.HasDBError(dbErrors) {
|
if httpserverutils.HasDBError(dbErrors) {
|
||||||
return nil, httpserverutils.NewHandlerErrorFromDBErrors("Some errors were encountered when loading transaction from the database:", dbErrors)
|
return nil, httpserverutils.NewErrorFromDBErrors("Some errors were encountered when loading transaction from the database:", dbErrors)
|
||||||
}
|
}
|
||||||
return convertTxDBModelToTxResponse(tx), nil
|
return convertTxDBModelToTxResponse(tx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionByHashHandler returns a transaction by a given transaction hash.
|
// GetTransactionByHashHandler returns a transaction by a given transaction hash.
|
||||||
func GetTransactionByHashHandler(txHash string) (interface{}, *httpserverutils.HandlerError) {
|
func GetTransactionByHashHandler(txHash string) (interface{}, error) {
|
||||||
if bytes, err := hex.DecodeString(txHash); err != nil || len(bytes) != daghash.HashSize {
|
if bytes, err := hex.DecodeString(txHash); err != nil || len(bytes) != daghash.HashSize {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity,
|
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity,
|
||||||
fmt.Sprintf("The given txhash is not a hex-encoded %d-byte hash.", daghash.HashSize))
|
errors.Errorf("The given txhash is not a hex-encoded %d-byte hash.", daghash.HashSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := database.DB()
|
db, err := database.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tx := &dbmodels.Transaction{}
|
tx := &dbmodels.Transaction{}
|
||||||
@ -64,25 +65,25 @@ func GetTransactionByHashHandler(txHash string) (interface{}, *httpserverutils.H
|
|||||||
dbResult := addTxPreloadedFields(query).First(&tx)
|
dbResult := addTxPreloadedFields(query).First(&tx)
|
||||||
dbErrors := dbResult.GetErrors()
|
dbErrors := dbResult.GetErrors()
|
||||||
if httpserverutils.IsDBRecordNotFoundError(dbErrors) {
|
if httpserverutils.IsDBRecordNotFoundError(dbErrors) {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusNotFound, "No transaction with the given txhash was found.")
|
return nil, httpserverutils.NewHandlerError(http.StatusNotFound, errors.Errorf("No transaction with the given txhash was found."))
|
||||||
}
|
}
|
||||||
if httpserverutils.HasDBError(dbErrors) {
|
if httpserverutils.HasDBError(dbErrors) {
|
||||||
return nil, httpserverutils.NewHandlerErrorFromDBErrors("Some errors were encountered when loading transaction from the database:", dbErrors)
|
return nil, httpserverutils.NewErrorFromDBErrors("Some errors were encountered when loading transaction from the database:", dbErrors)
|
||||||
}
|
}
|
||||||
return convertTxDBModelToTxResponse(tx), nil
|
return convertTxDBModelToTxResponse(tx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionsByAddressHandler searches for all transactions
|
// GetTransactionsByAddressHandler searches for all transactions
|
||||||
// where the given address is either an input or an output.
|
// where the given address is either an input or an output.
|
||||||
func GetTransactionsByAddressHandler(address string, skip uint64, limit uint64) (interface{}, *httpserverutils.HandlerError) {
|
func GetTransactionsByAddressHandler(address string, skip uint64, limit uint64) (interface{}, error) {
|
||||||
if limit > maxGetTransactionsLimit {
|
if limit > maxGetTransactionsLimit {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity,
|
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity,
|
||||||
fmt.Sprintf("The maximum allowed value for the limit is %d", maxGetTransactionsLimit))
|
errors.Errorf("The maximum allowed value for the limit is %d", maxGetTransactionsLimit))
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := database.DB()
|
db, err := database.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txs := []*dbmodels.Transaction{}
|
txs := []*dbmodels.Transaction{}
|
||||||
@ -90,7 +91,7 @@ func GetTransactionsByAddressHandler(address string, skip uint64, limit uint64)
|
|||||||
Joins("LEFT JOIN `transaction_outputs` ON `transaction_outputs`.`transaction_id` = `transactions`.`id`").
|
Joins("LEFT JOIN `transaction_outputs` ON `transaction_outputs`.`transaction_id` = `transactions`.`id`").
|
||||||
Joins("LEFT JOIN `addresses` AS `out_addresses` ON `out_addresses`.`id` = `transaction_outputs`.`address_id`").
|
Joins("LEFT JOIN `addresses` AS `out_addresses` ON `out_addresses`.`id` = `transaction_outputs`.`address_id`").
|
||||||
Joins("LEFT JOIN `transaction_inputs` ON `transaction_inputs`.`transaction_id` = `transactions`.`id`").
|
Joins("LEFT JOIN `transaction_inputs` ON `transaction_inputs`.`transaction_id` = `transactions`.`id`").
|
||||||
Joins("LEFT JOIN `transaction_outputs` AS `inputs_outs` ON `inputs_outs`.`id` = `transaction_inputs`.`transaction_output_id`").
|
Joins("LEFT JOIN `transaction_outputs` AS `inputs_outs` ON `inputs_outs`.`id` = `transaction_inputs`.`previous_transaction_output_id`").
|
||||||
Joins("LEFT JOIN `addresses` AS `in_addresses` ON `in_addresses`.`id` = `inputs_outs`.`address_id`").
|
Joins("LEFT JOIN `addresses` AS `in_addresses` ON `in_addresses`.`id` = `inputs_outs`.`address_id`").
|
||||||
Where("`out_addresses`.`address` = ?", address).
|
Where("`out_addresses`.`address` = ?", address).
|
||||||
Or("`in_addresses`.`address` = ?", address).
|
Or("`in_addresses`.`address` = ?", address).
|
||||||
@ -100,7 +101,7 @@ func GetTransactionsByAddressHandler(address string, skip uint64, limit uint64)
|
|||||||
dbResult := addTxPreloadedFields(query).Find(&txs)
|
dbResult := addTxPreloadedFields(query).Find(&txs)
|
||||||
dbErrors := dbResult.GetErrors()
|
dbErrors := dbResult.GetErrors()
|
||||||
if httpserverutils.HasDBError(dbErrors) {
|
if httpserverutils.HasDBError(dbErrors) {
|
||||||
return nil, httpserverutils.NewHandlerErrorFromDBErrors("Some errors were encountered when loading transactions from the database:", dbErrors)
|
return nil, httpserverutils.NewErrorFromDBErrors("Some errors were encountered when loading transactions from the database:", dbErrors)
|
||||||
}
|
}
|
||||||
txResponses := make([]*apimodels.TransactionResponse, len(txs))
|
txResponses := make([]*apimodels.TransactionResponse, len(txs))
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
@ -109,10 +110,10 @@ func GetTransactionsByAddressHandler(address string, skip uint64, limit uint64)
|
|||||||
return txResponses, nil
|
return txResponses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchSelectedTipBlueScore() (uint64, *httpserverutils.HandlerError) {
|
func fetchSelectedTipBlueScore() (uint64, error) {
|
||||||
db, err := database.DB()
|
db, err := database.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, httpserverutils.NewInternalServerHandlerError(err.Error())
|
return 0, err
|
||||||
}
|
}
|
||||||
block := &dbmodels.Block{}
|
block := &dbmodels.Block{}
|
||||||
dbResult := db.Order("blue_score DESC").
|
dbResult := db.Order("blue_score DESC").
|
||||||
@ -121,16 +122,16 @@ func fetchSelectedTipBlueScore() (uint64, *httpserverutils.HandlerError) {
|
|||||||
First(block)
|
First(block)
|
||||||
dbErrors := dbResult.GetErrors()
|
dbErrors := dbResult.GetErrors()
|
||||||
if httpserverutils.HasDBError(dbErrors) {
|
if httpserverutils.HasDBError(dbErrors) {
|
||||||
return 0, httpserverutils.NewHandlerErrorFromDBErrors("Some errors were encountered when loading transactions from the database:", dbErrors)
|
return 0, httpserverutils.NewErrorFromDBErrors("Some errors were encountered when loading transactions from the database:", dbErrors)
|
||||||
}
|
}
|
||||||
return block.BlueScore, nil
|
return block.BlueScore, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUTXOsByAddressHandler searches for all UTXOs that belong to a certain address.
|
// GetUTXOsByAddressHandler searches for all UTXOs that belong to a certain address.
|
||||||
func GetUTXOsByAddressHandler(address string) (interface{}, *httpserverutils.HandlerError) {
|
func GetUTXOsByAddressHandler(address string) (interface{}, error) {
|
||||||
db, err := database.DB()
|
db, err := database.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewInternalServerHandlerError(err.Error())
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var transactionOutputs []*dbmodels.TransactionOutput
|
var transactionOutputs []*dbmodels.TransactionOutput
|
||||||
@ -141,12 +142,12 @@ func GetUTXOsByAddressHandler(address string) (interface{}, *httpserverutils.Han
|
|||||||
Preload("Transaction.Subnetwork").
|
Preload("Transaction.Subnetwork").
|
||||||
Find(&transactionOutputs).GetErrors()
|
Find(&transactionOutputs).GetErrors()
|
||||||
if len(dbErrors) > 0 {
|
if len(dbErrors) > 0 {
|
||||||
return nil, httpserverutils.NewHandlerErrorFromDBErrors("Some errors were encountered when loading UTXOs from the database:", dbErrors)
|
return nil, httpserverutils.NewErrorFromDBErrors("Some errors were encountered when loading UTXOs from the database:", dbErrors)
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedTipBlueScore, hErr := fetchSelectedTipBlueScore()
|
selectedTipBlueScore, err := fetchSelectedTipBlueScore()
|
||||||
if hErr != nil {
|
if err != nil {
|
||||||
return nil, hErr
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
UTXOsResponses := make([]*apimodels.TransactionOutputResponse, len(transactionOutputs))
|
UTXOsResponses := make([]*apimodels.TransactionOutputResponse, len(transactionOutputs))
|
||||||
@ -154,7 +155,7 @@ func GetUTXOsByAddressHandler(address string) (interface{}, *httpserverutils.Han
|
|||||||
subnetworkID := &subnetworkid.SubnetworkID{}
|
subnetworkID := &subnetworkid.SubnetworkID{}
|
||||||
err := subnetworkid.Decode(subnetworkID, transactionOutput.Transaction.Subnetwork.SubnetworkID)
|
err := subnetworkid.Decode(subnetworkID, transactionOutput.Transaction.Subnetwork.SubnetworkID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewInternalServerHandlerError(fmt.Sprintf("Couldn't decode subnetwork id %s: %s", transactionOutput.Transaction.Subnetwork.SubnetworkID, err))
|
return nil, errors.Wrap(err, fmt.Sprintf("Couldn't decode subnetwork id %s", transactionOutput.Transaction.Subnetwork.SubnetworkID))
|
||||||
}
|
}
|
||||||
var acceptingBlockHash *string
|
var acceptingBlockHash *string
|
||||||
var confirmations uint64
|
var confirmations uint64
|
||||||
@ -188,24 +189,24 @@ func addTxPreloadedFields(query *gorm.DB) *gorm.DB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PostTransaction forwards a raw transaction to the JSON-RPC API server
|
// PostTransaction forwards a raw transaction to the JSON-RPC API server
|
||||||
func PostTransaction(requestBody []byte) *httpserverutils.HandlerError {
|
func PostTransaction(requestBody []byte) error {
|
||||||
client, err := jsonrpc.GetClient()
|
client, err := jsonrpc.GetClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httpserverutils.NewInternalServerHandlerError(err.Error())
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rawTx := &apimodels.RawTransaction{}
|
rawTx := &apimodels.RawTransaction{}
|
||||||
err = json.Unmarshal(requestBody, rawTx)
|
err = json.Unmarshal(requestBody, rawTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httpserverutils.NewHandlerErrorWithCustomClientMessage(http.StatusUnprocessableEntity,
|
return httpserverutils.NewHandlerErrorWithCustomClientMessage(http.StatusUnprocessableEntity,
|
||||||
fmt.Sprintf("Error unmarshalling request body: %s", err),
|
errors.Wrap(err, "Error unmarshalling request body"),
|
||||||
"The request body is not json-formatted")
|
"The request body is not json-formatted")
|
||||||
}
|
}
|
||||||
|
|
||||||
txBytes, err := hex.DecodeString(rawTx.RawTransaction)
|
txBytes, err := hex.DecodeString(rawTx.RawTransaction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httpserverutils.NewHandlerErrorWithCustomClientMessage(http.StatusUnprocessableEntity,
|
return httpserverutils.NewHandlerErrorWithCustomClientMessage(http.StatusUnprocessableEntity,
|
||||||
fmt.Sprintf("Error decoding hex raw transaction: %s", err),
|
errors.Wrap(err, "Error decoding hex raw transaction"),
|
||||||
"The raw transaction is not a hex-encoded transaction")
|
"The raw transaction is not a hex-encoded transaction")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,16 +215,16 @@ func PostTransaction(requestBody []byte) *httpserverutils.HandlerError {
|
|||||||
err = tx.BtcDecode(txReader, 0)
|
err = tx.BtcDecode(txReader, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httpserverutils.NewHandlerErrorWithCustomClientMessage(http.StatusUnprocessableEntity,
|
return httpserverutils.NewHandlerErrorWithCustomClientMessage(http.StatusUnprocessableEntity,
|
||||||
fmt.Sprintf("Error decoding raw transaction: %s", err),
|
errors.Wrap(err, "Error decoding raw transaction"),
|
||||||
"Error decoding raw transaction")
|
"Error decoding raw transaction")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.SendRawTransaction(tx, true)
|
_, err = client.SendRawTransaction(tx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if rpcErr, ok := err.(*btcjson.RPCError); ok && rpcErr.Code == btcjson.ErrRPCVerify {
|
if rpcErr, ok := err.(*btcjson.RPCError); ok && rpcErr.Code == btcjson.ErrRPCVerify {
|
||||||
return httpserverutils.NewHandlerError(http.StatusInternalServerError, rpcErr.Message)
|
return httpserverutils.NewHandlerError(http.StatusInternalServerError, err)
|
||||||
}
|
}
|
||||||
return httpserverutils.NewHandlerError(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -3,6 +3,7 @@ package server
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/daglabs/btcd/httpserverutils"
|
"github.com/daglabs/btcd/httpserverutils"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ const (
|
|||||||
defaultGetBlocksOrder = controllers.OrderAscending
|
defaultGetBlocksOrder = controllers.OrderAscending
|
||||||
)
|
)
|
||||||
|
|
||||||
func mainHandler(_ *httpserverutils.ServerContext, _ *http.Request, _ map[string]string, _ map[string]string, _ []byte) (interface{}, *httpserverutils.HandlerError) {
|
func mainHandler(_ *httpserverutils.ServerContext, _ *http.Request, _ map[string]string, _ map[string]string, _ []byte) (interface{}, error) {
|
||||||
return struct {
|
return struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}{
|
}{
|
||||||
@ -81,11 +82,11 @@ func addRoutes(router *mux.Router) {
|
|||||||
Methods("POST")
|
Methods("POST")
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertQueryParamToInt(queryParams map[string]string, param string, defaultValue int) (int, *httpserverutils.HandlerError) {
|
func convertQueryParamToInt(queryParams map[string]string, param string, defaultValue int) (int, error) {
|
||||||
if _, ok := queryParams[param]; ok {
|
if _, ok := queryParams[param]; ok {
|
||||||
intValue, err := strconv.Atoi(queryParams[param])
|
intValue, err := strconv.Atoi(queryParams[param])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity, fmt.Sprintf("Couldn't parse the '%s' query parameter: %s", param, err))
|
return 0, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity, errors.Wrap(err, fmt.Sprintf("Couldn't parse the '%s' query parameter", param)))
|
||||||
}
|
}
|
||||||
return intValue, nil
|
return intValue, nil
|
||||||
}
|
}
|
||||||
@ -93,72 +94,72 @@ func convertQueryParamToInt(queryParams map[string]string, param string, default
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getTransactionByIDHandler(_ *httpserverutils.ServerContext, _ *http.Request, routeParams map[string]string, _ map[string]string,
|
func getTransactionByIDHandler(_ *httpserverutils.ServerContext, _ *http.Request, routeParams map[string]string, _ map[string]string,
|
||||||
_ []byte) (interface{}, *httpserverutils.HandlerError) {
|
_ []byte) (interface{}, error) {
|
||||||
|
|
||||||
return controllers.GetTransactionByIDHandler(routeParams[routeParamTxID])
|
return controllers.GetTransactionByIDHandler(routeParams[routeParamTxID])
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTransactionByHashHandler(_ *httpserverutils.ServerContext, _ *http.Request, routeParams map[string]string, _ map[string]string,
|
func getTransactionByHashHandler(_ *httpserverutils.ServerContext, _ *http.Request, routeParams map[string]string, _ map[string]string,
|
||||||
_ []byte) (interface{}, *httpserverutils.HandlerError) {
|
_ []byte) (interface{}, error) {
|
||||||
|
|
||||||
return controllers.GetTransactionByHashHandler(routeParams[routeParamTxHash])
|
return controllers.GetTransactionByHashHandler(routeParams[routeParamTxHash])
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTransactionsByAddressHandler(_ *httpserverutils.ServerContext, _ *http.Request, routeParams map[string]string, queryParams map[string]string,
|
func getTransactionsByAddressHandler(_ *httpserverutils.ServerContext, _ *http.Request, routeParams map[string]string, queryParams map[string]string,
|
||||||
_ []byte) (interface{}, *httpserverutils.HandlerError) {
|
_ []byte) (interface{}, error) {
|
||||||
|
|
||||||
skip, hErr := convertQueryParamToInt(queryParams, queryParamSkip, 0)
|
skip, err := convertQueryParamToInt(queryParams, queryParamSkip, 0)
|
||||||
if hErr != nil {
|
if err != nil {
|
||||||
return nil, hErr
|
return nil, err
|
||||||
}
|
}
|
||||||
limit, hErr := convertQueryParamToInt(queryParams, queryParamLimit, defaultGetTransactionsLimit)
|
limit, err := convertQueryParamToInt(queryParams, queryParamLimit, defaultGetTransactionsLimit)
|
||||||
if hErr != nil {
|
if err != nil {
|
||||||
return nil, hErr
|
return nil, err
|
||||||
}
|
}
|
||||||
if _, ok := queryParams[queryParamLimit]; ok {
|
if _, ok := queryParams[queryParamLimit]; ok {
|
||||||
var err error
|
var err error
|
||||||
skip, err = strconv.Atoi(queryParams[queryParamLimit])
|
skip, err = strconv.Atoi(queryParams[queryParamLimit])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity,
|
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity,
|
||||||
fmt.Sprintf("Couldn't parse the '%s' query parameter: %s", queryParamLimit, err))
|
errors.Wrap(err, fmt.Sprintf("Couldn't parse the '%s' query parameter", queryParamLimit)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return controllers.GetTransactionsByAddressHandler(routeParams[routeParamAddress], uint64(skip), uint64(limit))
|
return controllers.GetTransactionsByAddressHandler(routeParams[routeParamAddress], uint64(skip), uint64(limit))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUTXOsByAddressHandler(_ *httpserverutils.ServerContext, _ *http.Request, routeParams map[string]string, _ map[string]string,
|
func getUTXOsByAddressHandler(_ *httpserverutils.ServerContext, _ *http.Request, routeParams map[string]string, _ map[string]string,
|
||||||
_ []byte) (interface{}, *httpserverutils.HandlerError) {
|
_ []byte) (interface{}, error) {
|
||||||
|
|
||||||
return controllers.GetUTXOsByAddressHandler(routeParams[routeParamAddress])
|
return controllers.GetUTXOsByAddressHandler(routeParams[routeParamAddress])
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBlockByHashHandler(_ *httpserverutils.ServerContext, _ *http.Request, routeParams map[string]string, _ map[string]string,
|
func getBlockByHashHandler(_ *httpserverutils.ServerContext, _ *http.Request, routeParams map[string]string, _ map[string]string,
|
||||||
_ []byte) (interface{}, *httpserverutils.HandlerError) {
|
_ []byte) (interface{}, error) {
|
||||||
|
|
||||||
return controllers.GetBlockByHashHandler(routeParams[routeParamBlockHash])
|
return controllers.GetBlockByHashHandler(routeParams[routeParamBlockHash])
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFeeEstimatesHandler(_ *httpserverutils.ServerContext, _ *http.Request, _ map[string]string, _ map[string]string,
|
func getFeeEstimatesHandler(_ *httpserverutils.ServerContext, _ *http.Request, _ map[string]string, _ map[string]string,
|
||||||
_ []byte) (interface{}, *httpserverutils.HandlerError) {
|
_ []byte) (interface{}, error) {
|
||||||
|
|
||||||
return controllers.GetFeeEstimatesHandler()
|
return controllers.GetFeeEstimatesHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBlocksHandler(_ *httpserverutils.ServerContext, _ *http.Request, _ map[string]string, queryParams map[string]string,
|
func getBlocksHandler(_ *httpserverutils.ServerContext, _ *http.Request, _ map[string]string, queryParams map[string]string,
|
||||||
_ []byte) (interface{}, *httpserverutils.HandlerError) {
|
_ []byte) (interface{}, error) {
|
||||||
|
|
||||||
skip, hErr := convertQueryParamToInt(queryParams, queryParamSkip, 0)
|
skip, err := convertQueryParamToInt(queryParams, queryParamSkip, 0)
|
||||||
if hErr != nil {
|
if err != nil {
|
||||||
return nil, hErr
|
return nil, err
|
||||||
}
|
}
|
||||||
limit, hErr := convertQueryParamToInt(queryParams, queryParamLimit, defaultGetBlocksLimit)
|
limit, err := convertQueryParamToInt(queryParams, queryParamLimit, defaultGetBlocksLimit)
|
||||||
if hErr != nil {
|
if err != nil {
|
||||||
return nil, hErr
|
return nil, err
|
||||||
}
|
}
|
||||||
order := defaultGetBlocksOrder
|
order := defaultGetBlocksOrder
|
||||||
if orderParamValue, ok := queryParams[queryParamOrder]; ok {
|
if orderParamValue, ok := queryParams[queryParamOrder]; ok {
|
||||||
if orderParamValue != controllers.OrderAscending && orderParamValue != controllers.OrderDescending {
|
if orderParamValue != controllers.OrderAscending && orderParamValue != controllers.OrderDescending {
|
||||||
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity, fmt.Sprintf("'%s' is not a valid value for the '%s' query parameter", orderParamValue, queryParamLimit))
|
return nil, httpserverutils.NewHandlerError(http.StatusUnprocessableEntity, errors.Errorf("'%s' is not a valid value for the '%s' query parameter", orderParamValue, queryParamLimit))
|
||||||
}
|
}
|
||||||
order = orderParamValue
|
order = orderParamValue
|
||||||
}
|
}
|
||||||
@ -166,6 +167,6 @@ func getBlocksHandler(_ *httpserverutils.ServerContext, _ *http.Request, _ map[s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func postTransactionHandler(_ *httpserverutils.ServerContext, _ *http.Request, _ map[string]string, _ map[string]string,
|
func postTransactionHandler(_ *httpserverutils.ServerContext, _ *http.Request, _ map[string]string, _ map[string]string,
|
||||||
requestBody []byte) (interface{}, *httpserverutils.HandlerError) {
|
requestBody []byte) (interface{}, error) {
|
||||||
return nil, controllers.PostTransaction(requestBody)
|
return nil, controllers.PostTransaction(requestBody)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/daglabs/btcd/faucet/database"
|
"github.com/daglabs/btcd/faucet/database"
|
||||||
"github.com/daglabs/btcd/httpserverutils"
|
"github.com/daglabs/btcd/httpserverutils"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
@ -23,43 +24,43 @@ func ipFromRequest(r *http.Request) (string, error) {
|
|||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateIPUsage(r *http.Request) *httpserverutils.HandlerError {
|
func validateIPUsage(r *http.Request) error {
|
||||||
db, err := database.DB()
|
db, err := database.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httpserverutils.NewInternalServerHandlerError(err.Error())
|
return err
|
||||||
}
|
}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
timeBeforeMinRequestInterval := now.Add(-minRequestInterval)
|
timeBeforeMinRequestInterval := now.Add(-minRequestInterval)
|
||||||
var count int
|
var count int
|
||||||
ip, err := ipFromRequest(r)
|
ip, err := ipFromRequest(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httpserverutils.NewInternalServerHandlerError(err.Error())
|
return err
|
||||||
}
|
}
|
||||||
dbResult := db.Model(&ipUse{}).Where(&ipUse{IP: ip}).Where("last_use BETWEEN ? AND ?", timeBeforeMinRequestInterval, now).Count(&count)
|
dbResult := db.Model(&ipUse{}).Where(&ipUse{IP: ip}).Where("last_use BETWEEN ? AND ?", timeBeforeMinRequestInterval, now).Count(&count)
|
||||||
dbErrors := dbResult.GetErrors()
|
dbErrors := dbResult.GetErrors()
|
||||||
if httpserverutils.HasDBError(dbErrors) {
|
if httpserverutils.HasDBError(dbErrors) {
|
||||||
return httpserverutils.NewHandlerErrorFromDBErrors("Some errors were encountered when checking the last use of an IP:", dbResult.GetErrors())
|
return httpserverutils.NewErrorFromDBErrors("Some errors were encountered when checking the last use of an IP:", dbResult.GetErrors())
|
||||||
}
|
}
|
||||||
if count != 0 {
|
if count != 0 {
|
||||||
return httpserverutils.NewHandlerError(http.StatusForbidden, "A user is allowed to to have one request from the faucet every 24 hours.")
|
return httpserverutils.NewHandlerError(http.StatusForbidden, errors.New("A user is allowed to to have one request from the faucet every 24 hours"))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateIPUsage(r *http.Request) *httpserverutils.HandlerError {
|
func updateIPUsage(r *http.Request) error {
|
||||||
db, err := database.DB()
|
db, err := database.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httpserverutils.NewInternalServerHandlerError(err.Error())
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, err := ipFromRequest(r)
|
ip, err := ipFromRequest(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httpserverutils.NewInternalServerHandlerError(err.Error())
|
return err
|
||||||
}
|
}
|
||||||
dbResult := db.Where(&ipUse{IP: ip}).Assign(&ipUse{LastUse: time.Now()}).FirstOrCreate(&ipUse{})
|
dbResult := db.Where(&ipUse{IP: ip}).Assign(&ipUse{LastUse: time.Now()}).FirstOrCreate(&ipUse{})
|
||||||
dbErrors := dbResult.GetErrors()
|
dbErrors := dbResult.GetErrors()
|
||||||
if httpserverutils.HasDBError(dbErrors) {
|
if httpserverutils.HasDBError(dbErrors) {
|
||||||
return httpserverutils.NewHandlerErrorFromDBErrors("Some errors were encountered when upserting the IP to the new date:", dbResult.GetErrors())
|
return httpserverutils.NewErrorFromDBErrors("Some errors were encountered when upserting the IP to the new date:", dbResult.GetErrors())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,10 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"github.com/daglabs/btcd/faucet/config"
|
"github.com/daglabs/btcd/faucet/config"
|
||||||
"github.com/daglabs/btcd/httpserverutils"
|
"github.com/daglabs/btcd/httpserverutils"
|
||||||
"github.com/daglabs/btcd/util"
|
"github.com/daglabs/btcd/util"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ type requestMoneyData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func requestMoneyHandler(_ *httpserverutils.ServerContext, r *http.Request, _ map[string]string, _ map[string]string,
|
func requestMoneyHandler(_ *httpserverutils.ServerContext, r *http.Request, _ map[string]string, _ map[string]string,
|
||||||
requestBody []byte) (interface{}, *httpserverutils.HandlerError) {
|
requestBody []byte) (interface{}, error) {
|
||||||
hErr := validateIPUsage(r)
|
hErr := validateIPUsage(r)
|
||||||
if hErr != nil {
|
if hErr != nil {
|
||||||
return nil, hErr
|
return nil, hErr
|
||||||
@ -60,18 +60,18 @@ func requestMoneyHandler(_ *httpserverutils.ServerContext, r *http.Request, _ ma
|
|||||||
err := json.Unmarshal(requestBody, requestData)
|
err := json.Unmarshal(requestBody, requestData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewHandlerErrorWithCustomClientMessage(http.StatusUnprocessableEntity,
|
return nil, httpserverutils.NewHandlerErrorWithCustomClientMessage(http.StatusUnprocessableEntity,
|
||||||
fmt.Sprintf("Error unmarshalling request body: %s", err),
|
errors.Wrap(err, "Error unmarshalling request body"),
|
||||||
"The request body is not json-formatted")
|
"The request body is not json-formatted")
|
||||||
}
|
}
|
||||||
address, err := util.DecodeAddress(requestData.Address, config.ActiveNetParams().Prefix)
|
address, err := util.DecodeAddress(requestData.Address, config.ActiveNetParams().Prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewHandlerErrorWithCustomClientMessage(http.StatusUnprocessableEntity,
|
return nil, httpserverutils.NewHandlerErrorWithCustomClientMessage(http.StatusUnprocessableEntity,
|
||||||
fmt.Sprintf("Error decoding address: %s", err),
|
errors.Wrap(err, "Error decoding address"),
|
||||||
"Error decoding address")
|
"Error decoding address")
|
||||||
}
|
}
|
||||||
tx, err := sendToAddress(address)
|
tx, err := sendToAddress(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httpserverutils.NewInternalServerHandlerError(err.Error())
|
return nil, err
|
||||||
}
|
}
|
||||||
hErr = updateIPUsage(r)
|
hErr = updateIPUsage(r)
|
||||||
if hErr != nil {
|
if hErr != nil {
|
||||||
|
@ -13,29 +13,29 @@ import (
|
|||||||
// a rest route handler or a middleware.
|
// a rest route handler or a middleware.
|
||||||
type HandlerError struct {
|
type HandlerError struct {
|
||||||
Code int
|
Code int
|
||||||
Message string
|
Cause error
|
||||||
ClientMessage string
|
ClientMessage string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hErr *HandlerError) Error() string {
|
func (hErr *HandlerError) Error() string {
|
||||||
return hErr.Message
|
return hErr.Cause.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHandlerError returns a HandlerError with the given code and message.
|
// NewHandlerError returns a HandlerError with the given code and message.
|
||||||
func NewHandlerError(code int, message string) *HandlerError {
|
func NewHandlerError(code int, err error) error {
|
||||||
return &HandlerError{
|
return &HandlerError{
|
||||||
Code: code,
|
Code: code,
|
||||||
Message: message,
|
Cause: err,
|
||||||
ClientMessage: message,
|
ClientMessage: err.Error(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHandlerErrorWithCustomClientMessage returns a HandlerError with
|
// NewHandlerErrorWithCustomClientMessage returns a HandlerError with
|
||||||
// the given code, message and client error message.
|
// the given code, message and client error message.
|
||||||
func NewHandlerErrorWithCustomClientMessage(code int, message, clientMessage string) *HandlerError {
|
func NewHandlerErrorWithCustomClientMessage(code int, err error, clientMessage string) error {
|
||||||
return &HandlerError{
|
return &HandlerError{
|
||||||
Code: code,
|
Code: code,
|
||||||
Message: message,
|
Cause: err,
|
||||||
ClientMessage: clientMessage,
|
ClientMessage: clientMessage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,8 +43,8 @@ func NewHandlerErrorWithCustomClientMessage(code int, message, clientMessage str
|
|||||||
// NewInternalServerHandlerError returns a HandlerError with
|
// NewInternalServerHandlerError returns a HandlerError with
|
||||||
// the given message, and the http.StatusInternalServerError
|
// the given message, and the http.StatusInternalServerError
|
||||||
// status text as client message.
|
// status text as client message.
|
||||||
func NewInternalServerHandlerError(message string) *HandlerError {
|
func NewInternalServerHandlerError(err error) error {
|
||||||
return NewHandlerErrorWithCustomClientMessage(http.StatusInternalServerError, message, http.StatusText(http.StatusInternalServerError))
|
return NewHandlerErrorWithCustomClientMessage(http.StatusInternalServerError, err, http.StatusText(http.StatusInternalServerError))
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewErrorFromDBErrors takes a slice of database errors and a prefix, and
|
// NewErrorFromDBErrors takes a slice of database errors and a prefix, and
|
||||||
@ -58,13 +58,6 @@ func NewErrorFromDBErrors(prefix string, dbErrors []error) error {
|
|||||||
return errors.Errorf("%s [%s]", prefix, strings.Join(dbErrorsStrings, ","))
|
return errors.Errorf("%s [%s]", prefix, strings.Join(dbErrorsStrings, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHandlerErrorFromDBErrors takes a slice of database errors and a prefix, and
|
|
||||||
// returns an HandlerError with error code http.StatusInternalServerError with
|
|
||||||
// all of the database errors formatted to one string with the given prefix
|
|
||||||
func NewHandlerErrorFromDBErrors(prefix string, dbErrors []error) *HandlerError {
|
|
||||||
return NewInternalServerHandlerError(NewErrorFromDBErrors(prefix, dbErrors).Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDBRecordNotFoundError returns true if the given dbErrors contains only a RecordNotFound error
|
// IsDBRecordNotFoundError returns true if the given dbErrors contains only a RecordNotFound error
|
||||||
func IsDBRecordNotFoundError(dbErrors []error) bool {
|
func IsDBRecordNotFoundError(dbErrors []error) bool {
|
||||||
return len(dbErrors) == 1 && gorm.IsRecordNotFoundError(dbErrors[0])
|
return len(dbErrors) == 1 && gorm.IsRecordNotFoundError(dbErrors[0])
|
||||||
@ -88,9 +81,13 @@ func (err *ClientError) Error() string {
|
|||||||
|
|
||||||
// SendErr takes a HandlerError and create a ClientError out of it that is sent
|
// SendErr takes a HandlerError and create a ClientError out of it that is sent
|
||||||
// to the http client.
|
// to the http client.
|
||||||
func SendErr(ctx *ServerContext, w http.ResponseWriter, hErr *HandlerError) {
|
func SendErr(ctx *ServerContext, w http.ResponseWriter, err error) {
|
||||||
errMsg := fmt.Sprintf("got error: %s", hErr)
|
var hErr *HandlerError
|
||||||
ctx.Warnf(errMsg)
|
var ok bool
|
||||||
|
if hErr, ok = err.(*HandlerError); !ok {
|
||||||
|
hErr = NewInternalServerHandlerError(err).(*HandlerError)
|
||||||
|
}
|
||||||
|
ctx.Warnf("got error: %s", err)
|
||||||
w.WriteHeader(hErr.Code)
|
w.WriteHeader(hErr.Code)
|
||||||
SendJSONResponse(w, &ClientError{
|
SendJSONResponse(w, &ClientError{
|
||||||
ErrorCode: hErr.Code,
|
ErrorCode: hErr.Code,
|
||||||
|
@ -2,6 +2,7 @@ package httpserverutils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
)
|
)
|
||||||
@ -38,10 +39,16 @@ func RecoveryMiddleware(h http.Handler) http.Handler {
|
|||||||
defer func() {
|
defer func() {
|
||||||
recoveryErr := recover()
|
recoveryErr := recover()
|
||||||
if recoveryErr != nil {
|
if recoveryErr != nil {
|
||||||
|
var recoveryErrAsError error
|
||||||
|
if rErr, ok := recoveryErr.(error); ok {
|
||||||
|
recoveryErrAsError = rErr
|
||||||
|
} else {
|
||||||
|
recoveryErrAsError = errors.Errorf("%s", recoveryErr)
|
||||||
|
}
|
||||||
recoveryErrStr := fmt.Sprintf("%s", recoveryErr)
|
recoveryErrStr := fmt.Sprintf("%s", recoveryErr)
|
||||||
log.Criticalf("Fatal error: %s", recoveryErrStr)
|
log.Criticalf("Fatal error: %+v", recoveryErrStr)
|
||||||
log.Criticalf("Stack trace: %s", debug.Stack())
|
log.Criticalf("Stack trace: %s", debug.Stack())
|
||||||
SendErr(ctx, w, NewInternalServerHandlerError(recoveryErrStr))
|
SendErr(ctx, w, recoveryErrAsError)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
h.ServeHTTP(w, r)
|
h.ServeHTTP(w, r)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package httpserverutils
|
package httpserverutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@ -11,7 +11,7 @@ import (
|
|||||||
// MakeHandler wrapper and gets the relevant request fields
|
// MakeHandler wrapper and gets the relevant request fields
|
||||||
// from it.
|
// from it.
|
||||||
type HandlerFunc func(ctx *ServerContext, r *http.Request, routeParams map[string]string, queryParams map[string]string, requestBody []byte) (
|
type HandlerFunc func(ctx *ServerContext, r *http.Request, routeParams map[string]string, queryParams map[string]string, requestBody []byte) (
|
||||||
interface{}, *HandlerError)
|
interface{}, error)
|
||||||
|
|
||||||
// MakeHandler is a wrapper function that takes a handler in the form of HandlerFunc
|
// MakeHandler is a wrapper function that takes a handler in the form of HandlerFunc
|
||||||
// and returns a function that can be used as a handler in mux.Router.HandleFunc.
|
// and returns a function that can be used as a handler in mux.Router.HandleFunc.
|
||||||
@ -24,19 +24,19 @@ func MakeHandler(handler HandlerFunc) func(http.ResponseWriter, *http.Request) {
|
|||||||
var err error
|
var err error
|
||||||
requestBody, err = ioutil.ReadAll(r.Body)
|
requestBody, err = ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
SendErr(ctx, w, NewInternalServerHandlerError("Error reading POST data"))
|
SendErr(ctx, w, errors.New("Error reading POST data"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flattenedQueryParams, hErr := flattenQueryParams(r.URL.Query())
|
flattenedQueryParams, err := flattenQueryParams(r.URL.Query())
|
||||||
if hErr != nil {
|
if err != nil {
|
||||||
SendErr(ctx, w, hErr)
|
SendErr(ctx, w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response, hErr := handler(ctx, r, mux.Vars(r), flattenedQueryParams, requestBody)
|
response, err := handler(ctx, r, mux.Vars(r), flattenedQueryParams, requestBody)
|
||||||
if hErr != nil {
|
if err != nil {
|
||||||
SendErr(ctx, w, hErr)
|
SendErr(ctx, w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if response != nil {
|
if response != nil {
|
||||||
@ -45,11 +45,11 @@ func MakeHandler(handler HandlerFunc) func(http.ResponseWriter, *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func flattenQueryParams(queryParams map[string][]string) (map[string]string, *HandlerError) {
|
func flattenQueryParams(queryParams map[string][]string) (map[string]string, error) {
|
||||||
flattenedMap := make(map[string]string)
|
flattenedMap := make(map[string]string)
|
||||||
for param, valuesSlice := range queryParams {
|
for param, valuesSlice := range queryParams {
|
||||||
if len(valuesSlice) > 1 {
|
if len(valuesSlice) > 1 {
|
||||||
return nil, NewHandlerError(http.StatusUnprocessableEntity, fmt.Sprintf("Couldn't parse the '%s' query parameter:"+
|
return nil, NewHandlerError(http.StatusUnprocessableEntity, errors.Errorf("Couldn't parse the '%s' query parameter:"+
|
||||||
" expected a single value but got multiple values", param))
|
" expected a single value but got multiple values", param))
|
||||||
}
|
}
|
||||||
flattenedMap[param] = valuesSlice[0]
|
flattenedMap[param] = valuesSlice[0]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user