Skip to content

Commit 7487043

Browse files
committed
feat: parse discord errors response into readable format
1 parent 46d5e81 commit 7487043

File tree

6 files changed

+166
-1
lines changed

6 files changed

+166
-1
lines changed

rest/rest_error.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ package rest
33
import (
44
"errors"
55
"fmt"
6+
"maps"
67
"net/http"
8+
"slices"
9+
"strings"
710

811
"github.com/disgoorg/json/v2"
912
)
@@ -55,7 +58,11 @@ func (e *Error) Is(target error) bool {
5558
// Error returns the error formatted as string
5659
func (e *Error) Error() string {
5760
if e.Code != 0 {
58-
return fmt.Sprintf("%d: %s", e.Code, e.Message)
61+
msg := fmt.Sprintf("%d: %s", e.Code, e.Message)
62+
if e.Code == 50035 {
63+
msg += fmt.Sprintf("\n%s", printErrors(e.Errors))
64+
}
65+
return msg
5966
}
6067
return fmt.Sprintf("Status: %s, Body: %s", e.Response.Status, string(e.RsBody))
6168
}
@@ -64,3 +71,37 @@ func (e *Error) Error() string {
6471
func (e *Error) String() string {
6572
return e.Error()
6673
}
74+
75+
func printErrors(errors json.RawMessage) string {
76+
var m map[string]any
77+
if err := json.Unmarshal(errors, &m); err != nil {
78+
return ""
79+
}
80+
81+
return parseErrors("", m)
82+
}
83+
84+
func parseErrors(prefix string, err map[string]any) string {
85+
if errs, ok := err["_errors"]; ok {
86+
var s []string
87+
for _, e := range errs.([]any) {
88+
m := e.(map[string]any)
89+
s = append(s, fmt.Sprintf("%s -> %s: %s", prefix, m["code"], m["message"]))
90+
}
91+
return strings.Join(s, "\n")
92+
}
93+
94+
var s []string
95+
for _, k := range slices.Sorted(maps.Keys(err)) {
96+
m := err[k].(map[string]any)
97+
98+
nextPrefix := prefix
99+
if nextPrefix != "" {
100+
nextPrefix += " -> "
101+
}
102+
103+
s = append(s, parseErrors(nextPrefix+k, m))
104+
}
105+
106+
return strings.Join(s, "\n")
107+
}

rest/rest_error_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package rest
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
8+
"github.com/disgoorg/json/v2"
9+
)
10+
11+
func TestError_Error(t *testing.T) {
12+
data := []struct {
13+
Name string
14+
TestFile string
15+
Expected string
16+
}{
17+
{
18+
Name: "array error",
19+
TestFile: "array_error.json",
20+
Expected: "50035: Invalid Form Body\nactivities -> 0 -> platform -> BASE_TYPE_CHOICES: Value must be one of ('desktop', 'android', 'ios').\nactivities -> 0 -> type -> BASE_TYPE_CHOICES: Value must be one of (0, 1, 2, 3, 4, 5).",
21+
},
22+
{
23+
Name: "object error",
24+
TestFile: "object_error.json",
25+
Expected: "50035: Invalid Form Body\naccess_token -> BASE_TYPE_REQUIRED: This field is required",
26+
},
27+
{
28+
Name: "request error",
29+
TestFile: "request_error.json",
30+
Expected: "50035: Invalid Form Body\n -> APPLICATION_COMMAND_TOO_LARGE: Command exceeds maximum size (8000)",
31+
},
32+
{
33+
Name: "other error",
34+
TestFile: "other_error.json",
35+
Expected: "50035: Invalid Form Body\ndata -> components -> BASE_TYPE_MAX_LENGTH: Must be 5 or fewer in length.",
36+
},
37+
}
38+
39+
for _, d := range data {
40+
t.Run(d.Name, func(t *testing.T) {
41+
raw, err := os.ReadFile(filepath.Join("testdata", d.TestFile))
42+
if err != nil {
43+
t.Fatal(err)
44+
}
45+
var restErr *Error
46+
if err = json.Unmarshal(raw, &restErr); err != nil {
47+
t.Fatal(err)
48+
}
49+
50+
actual := restErr.Error()
51+
if actual != d.Expected {
52+
t.Errorf("got %q, want %q", actual, d.Expected)
53+
}
54+
})
55+
}
56+
}

rest/testdata/array_error.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"code": 50035,
3+
"message": "Invalid Form Body",
4+
"errors": {
5+
"activities": {
6+
"0": {
7+
"platform": {
8+
"_errors": [
9+
{
10+
"code": "BASE_TYPE_CHOICES",
11+
"message": "Value must be one of ('desktop', 'android', 'ios')."
12+
}
13+
]
14+
},
15+
"type": {
16+
"_errors": [
17+
{
18+
"code": "BASE_TYPE_CHOICES",
19+
"message": "Value must be one of (0, 1, 2, 3, 4, 5)."
20+
}
21+
]
22+
}
23+
}
24+
}
25+
}
26+
}

rest/testdata/object_error.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"code": 50035,
3+
"message": "Invalid Form Body",
4+
"errors": {
5+
"access_token": {
6+
"_errors": [
7+
{
8+
"code": "BASE_TYPE_REQUIRED",
9+
"message": "This field is required"
10+
}
11+
]
12+
}
13+
}
14+
}

rest/testdata/other_error.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"code": 50035,
3+
"message": "Invalid Form Body",
4+
"errors": {
5+
"data": {
6+
"components": {
7+
"_errors": [
8+
{
9+
"code": "BASE_TYPE_MAX_LENGTH",
10+
"message": "Must be 5 or fewer in length."
11+
}
12+
]
13+
}
14+
}
15+
}
16+
}

rest/testdata/request_error.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"code": 50035,
3+
"message": "Invalid Form Body",
4+
"errors": {
5+
"_errors": [
6+
{
7+
"code": "APPLICATION_COMMAND_TOO_LARGE",
8+
"message": "Command exceeds maximum size (8000)"
9+
}
10+
]
11+
}
12+
}

0 commit comments

Comments
 (0)