Skip to content
This repository has been archived by the owner on Oct 21, 2024. It is now read-only.

Commit

Permalink
feat(BUX-156): improve http error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
arkadiuszos4chain committed Aug 9, 2023
1 parent 6ffa739 commit 3b94345
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 35 deletions.
29 changes: 2 additions & 27 deletions broadcast/internal/arc/arc_submit_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"errors"
"net/http"
"strconv"

"github.com/bitcoin-sv/go-broadcast-client/broadcast"
Expand Down Expand Up @@ -76,7 +75,7 @@ func submitTransaction(ctx context.Context, arc *ArcClient, tx *broadcast.Transa
pld,
)
if err != nil {
return nil, handleHttpError(resp, err)
return nil, arc_utils.HandleHttpError(err)
}

model := broadcast.SubmitTxResponse{}
Expand Down Expand Up @@ -108,7 +107,7 @@ func submitBatchTransactions(ctx context.Context, arc *ArcClient, txs []*broadca
pld,
)
if err != nil {
return nil, handleHttpError(resp, err)
return nil, arc_utils.HandleHttpError(err)
}

var model []*broadcast.SubmitTxResponse
Expand Down Expand Up @@ -180,27 +179,3 @@ func validateSubmitTxResponse(model *broadcast.SubmitTxResponse) error {

return nil
}

func handleHttpError(response *http.Response, httpClientError error) error {
if response != nil { // client respond with code different than 2xx
var err error

switch response.StatusCode {
case 400:
err = arc_utils.DecodeArcError(response.Body)
case 422: // Unprocessable entity - with IETF RFC 7807 Error object
err = arc_utils.DecodeArcError(response.Body)
case 465: // Fee too low
err = arc_utils.DecodeArcError(response.Body)
case 466: // Conflicting transaction found
err = arc_utils.DecodeArcError(response.Body)

default:
err = errors.New(response.Status)
}

return err
}

return httpClientError // http client internal error
}
46 changes: 40 additions & 6 deletions broadcast/internal/arc/utils/arc_utils.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
package arc_utils

import (
"bytes"
"encoding/json"
"io"

"github.com/bitcoin-sv/go-broadcast-client/broadcast"
"github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/httpclient"
)

func DecodeArcError(body io.ReadCloser) error {
resultError := broadcast.ArcError{}
err := json.NewDecoder(body).Decode(&resultError)
func HandleHttpError(httpClientError error) error {
noSuccessResponseErr, ok := httpClientError.(httpclient.HttpClientError)

if err != nil {
return broadcast.ErrUnableToDecodeResponse
if ok { // client respond with code different than 2xx
var err error

switch noSuccessResponseErr.Response.StatusCode {
case 400:
err = decodeArcError(noSuccessResponseErr)
case 422: // Unprocessable entity - with IETF RFC 7807 Error object
err = decodeArcError(noSuccessResponseErr)
case 465: // Fee too low
err = decodeArcError(noSuccessResponseErr)
case 466: // Conflicting transaction found
err = decodeArcError(noSuccessResponseErr)

default:
err = noSuccessResponseErr
}

return err
}

return resultError
return httpClientError // http client internal error
}

func DecodeResponseBody(body io.ReadCloser, resultOutput any) error {
Expand All @@ -26,3 +43,20 @@ func DecodeResponseBody(body io.ReadCloser, resultOutput any) error {

return nil
}

func decodeArcError(httpErr httpclient.HttpClientError) error {
response := httpErr.Response
// duplicate stream
var buffer bytes.Buffer
bodyReader := io.TeeReader(response.Body, &buffer)

resultError := broadcast.ArcError{}
json.NewDecoder(bodyReader).Decode(&resultError) // ignore decoding error

if resultError.Title != "" {
return resultError
}

// miner returns an error with an invalid schema
return httpErr
}
13 changes: 11 additions & 2 deletions broadcast/internal/httpclient/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package httpclient
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"

Expand Down Expand Up @@ -35,6 +35,15 @@ type HTTPRequest struct {
Headers map[string]string
}

type HttpClientError struct {
Response *http.Response
}

func (err HttpClientError) Error() string {
body, _ := io.ReadAll(err.Response.Body)
return fmt.Sprintf("server responded with no-success code. details: { statusCode: %d, body: %s }", err.Response.StatusCode, body)
}

func (pld *HTTPRequest) AddHeader(key, value string) {
if pld.Headers == nil {
pld.Headers = make(map[string]string)
Expand Down Expand Up @@ -89,7 +98,7 @@ func (hc *HTTPClient) DoRequest(ctx context.Context, pld HTTPRequest) (*http.Res
return resp, nil
}

return resp, errors.New("server responded with no-success code")
return nil, HttpClientError{resp}
}

func hasSuccessCode(resp *http.Response) bool {
Expand Down

0 comments on commit 3b94345

Please sign in to comment.