...
1
15 package errutil
16
17 import (
18 "encoding/json"
19 "fmt"
20 "io"
21 "net/http"
22 "strings"
23 "unicode"
24 )
25
26
27
28
29
30 var maxErrorBytes int64 = 8 * 1024
31
32
33 type requestError struct {
34 Code string `json:"code"`
35 Message string `json:"message"`
36 }
37
38
39 func (e requestError) Error() string {
40 code := strings.Map(func(r rune) rune {
41 if r == '_' {
42 return ' '
43 }
44 return unicode.ToLower(r)
45 }, e.Code)
46 if e.Message == "" {
47 return code
48 }
49 return fmt.Sprintf("%s: %s", code, e.Message)
50 }
51
52
53 type requestErrors []requestError
54
55
56 func (errs requestErrors) Error() string {
57 switch len(errs) {
58 case 0:
59 return "<nil>"
60 case 1:
61 return errs[0].Error()
62 }
63 var errmsgs []string
64 for _, err := range errs {
65 errmsgs = append(errmsgs, err.Error())
66 }
67 return strings.Join(errmsgs, "; ")
68 }
69
70
71 func ParseErrorResponse(resp *http.Response) error {
72 var errmsg string
73 var body struct {
74 Errors requestErrors `json:"errors"`
75 }
76 lr := io.LimitReader(resp.Body, maxErrorBytes)
77 if err := json.NewDecoder(lr).Decode(&body); err == nil && len(body.Errors) > 0 {
78 errmsg = body.Errors.Error()
79 } else {
80 errmsg = http.StatusText(resp.StatusCode)
81 }
82 return fmt.Errorf("%s %q: unexpected status code %d: %s", resp.Request.Method, resp.Request.URL, resp.StatusCode, errmsg)
83 }
84
View as plain text