github.com/aavshr/aws-sdk-go@v1.41.3/private/protocol/jsonrpc/unmarshal_error.go (about)

     1  package jsonrpc
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"strings"
     9  
    10  	"github.com/aavshr/aws-sdk-go/aws/awserr"
    11  	"github.com/aavshr/aws-sdk-go/aws/request"
    12  	"github.com/aavshr/aws-sdk-go/private/protocol"
    13  	"github.com/aavshr/aws-sdk-go/private/protocol/json/jsonutil"
    14  )
    15  
    16  // UnmarshalTypedError provides unmarshaling errors API response errors
    17  // for both typed and untyped errors.
    18  type UnmarshalTypedError struct {
    19  	exceptions map[string]func(protocol.ResponseMetadata) error
    20  }
    21  
    22  // NewUnmarshalTypedError returns an UnmarshalTypedError initialized for the
    23  // set of exception names to the error unmarshalers
    24  func NewUnmarshalTypedError(exceptions map[string]func(protocol.ResponseMetadata) error) *UnmarshalTypedError {
    25  	return &UnmarshalTypedError{
    26  		exceptions: exceptions,
    27  	}
    28  }
    29  
    30  // UnmarshalError attempts to unmarshal the HTTP response error as a known
    31  // error type. If unable to unmarshal the error type, the generic SDK error
    32  // type will be used.
    33  func (u *UnmarshalTypedError) UnmarshalError(
    34  	resp *http.Response,
    35  	respMeta protocol.ResponseMetadata,
    36  ) (error, error) {
    37  
    38  	var buf bytes.Buffer
    39  	var jsonErr jsonErrorResponse
    40  	teeReader := io.TeeReader(resp.Body, &buf)
    41  	err := jsonutil.UnmarshalJSONError(&jsonErr, teeReader)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	body := ioutil.NopCloser(&buf)
    46  
    47  	// Code may be separated by hash(#), with the last element being the code
    48  	// used by the SDK.
    49  	codeParts := strings.SplitN(jsonErr.Code, "#", 2)
    50  	code := codeParts[len(codeParts)-1]
    51  	msg := jsonErr.Message
    52  
    53  	if fn, ok := u.exceptions[code]; ok {
    54  		// If exception code is know, use associated constructor to get a value
    55  		// for the exception that the JSON body can be unmarshaled into.
    56  		v := fn(respMeta)
    57  		err := jsonutil.UnmarshalJSONCaseInsensitive(v, body)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  
    62  		return v, nil
    63  	}
    64  
    65  	// fallback to unmodeled generic exceptions
    66  	return awserr.NewRequestFailure(
    67  		awserr.New(code, msg, nil),
    68  		respMeta.StatusCode,
    69  		respMeta.RequestID,
    70  	), nil
    71  }
    72  
    73  // UnmarshalErrorHandler is a named request handler for unmarshaling jsonrpc
    74  // protocol request errors
    75  var UnmarshalErrorHandler = request.NamedHandler{
    76  	Name: "awssdk.jsonrpc.UnmarshalError",
    77  	Fn:   UnmarshalError,
    78  }
    79  
    80  // UnmarshalError unmarshals an error response for a JSON RPC service.
    81  func UnmarshalError(req *request.Request) {
    82  	defer req.HTTPResponse.Body.Close()
    83  
    84  	var jsonErr jsonErrorResponse
    85  	err := jsonutil.UnmarshalJSONError(&jsonErr, req.HTTPResponse.Body)
    86  	if err != nil {
    87  		req.Error = awserr.NewRequestFailure(
    88  			awserr.New(request.ErrCodeSerialization,
    89  				"failed to unmarshal error message", err),
    90  			req.HTTPResponse.StatusCode,
    91  			req.RequestID,
    92  		)
    93  		return
    94  	}
    95  
    96  	codes := strings.SplitN(jsonErr.Code, "#", 2)
    97  	req.Error = awserr.NewRequestFailure(
    98  		awserr.New(codes[len(codes)-1], jsonErr.Message, nil),
    99  		req.HTTPResponse.StatusCode,
   100  		req.RequestID,
   101  	)
   102  }
   103  
   104  type jsonErrorResponse struct {
   105  	Code    string `json:"__type"`
   106  	Message string `json:"message"`
   107  }