Skip to content

Commit

Permalink
Add support for multiple errors (#181)
Browse files Browse the repository at this point in the history
  • Loading branch information
jerbob92 authored Jun 18, 2024
1 parent f96e2f9 commit ba07d56
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 1 deletion.
58 changes: 57 additions & 1 deletion error.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,70 @@ var ErrorTypeAssert = Error{
Message: "Type assertion failed",
}

type ErrorDetail struct {
Multiple bool
Errors map[int]map[string][]string
}

func (ed *ErrorDetail) DetailsForRow(row int) (map[string][]string, error) {
if !ed.Multiple {
return nil, errors.New("error contains a single error, use Error()")
}

rowDetail, ok := ed.Errors[row]
if !ok {
return nil, nil
}

return rowDetail, nil
}

func (ed *ErrorDetail) Details() (map[string][]string, error) {
if ed.Multiple {
return nil, errors.New("error contains multiple errors, use ErrorForRow()")
}

return ed.Errors[0], nil
}

func (ed *ErrorDetail) UnmarshalJSON(data []byte) error {
// First attempt to unmarshal singular.
var singularErr map[string][]string
err := json.Unmarshal(data, &singularErr)
if err == nil {
ed.Errors = map[int]map[string][]string{
0: singularErr,
}
return nil
}

// Then attempt to unmarshal multiple.
var multipleErr map[int]map[string][]string
err = json.Unmarshal(data, &multipleErr)
if err == nil {
ed.Errors = multipleErr
ed.Multiple = true
return nil
}

return err
}

func (ed *ErrorDetail) MarshalJSON() ([]byte, error) {
if ed.Multiple {
return json.Marshal(ed.Errors)
}
return json.Marshal(ed.Errors[0])
}

type Error struct {
Err error `json:"-"`

HTTPStatusCode int `json:"status"`
Message string `json:"error"`
ErrorCode string `json:"code"`

ErrorDetail map[string][]string `json:"error_details,omitempty"`
ErrorDetail *ErrorDetail `json:"error_details,omitempty"`
}

func (e Error) Error() string {
Expand Down
115 changes: 115 additions & 0 deletions error_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package lago

import (
"encoding/json"
"errors"
"testing"
)
Expand All @@ -21,3 +22,117 @@ func TestErrorNoErr(t *testing.T) {
}
t.Logf("%s", noErr.Error())
}

func TestErrorDetails(t *testing.T) {
var tests = []struct {
name string
input string
want *Error
}{
{
name: "Single detail",
input: `{
"status": 422,
"error": "Unprocessable Entity",
"code": "validation_errors",
"error_details": {
"transaction_id": [
"value_already_exist"
]
}
}`,
want: &Error{
HTTPStatusCode: 422,
Message: "Unprocessable Entity",
ErrorCode: "validation_errors",
ErrorDetail: &ErrorDetail{
Multiple: false,
Errors: map[int]map[string][]string{
0: {
"transaction_id": {
"value_already_exist",
},
},
},
},
},
},
{
name: "Multiple details",
input: `{
"status": 422,
"error": "Unprocessable Entity",
"code": "validation_errors",
"error_details": {
"0": {
"transaction_id": [
"value_already_exist"
]
},
"1": {
"transaction_id": [
"value_already_exist"
]
},
"2": {
"transaction_id": [
"value_already_exist"
]
}
}
}`,
want: &Error{
HTTPStatusCode: 422,
Message: "Unprocessable Entity",
ErrorCode: "validation_errors",
ErrorDetail: &ErrorDetail{
Multiple: true,
Errors: map[int]map[string][]string{
0: {
"transaction_id": {
"value_already_exist",
},
},
1: {
"transaction_id": {
"value_already_exist",
},
},
2: {
"transaction_id": {
"value_already_exist",
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
errObj := &Error{}
err := json.Unmarshal([]byte(tt.input), errObj)
if err != nil {
t.Errorf("got error %s", err.Error())
return
}

expectErr, err := json.Marshal(tt.want)
if err != nil {
t.Errorf("got error %s", err.Error())
return
}

gotErr, err := json.Marshal(errObj)
if err != nil {
t.Errorf("got error %s", err.Error())
return
}

if string(expectErr) != string(gotErr) {
t.Errorf("got error %s, but expected error %s", string(gotErr), string(expectErr))
return
}
})
}
}

0 comments on commit ba07d56

Please sign in to comment.