0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-08-25 04:45:46 +00:00

fix(api): improve API response error handling (#2043)

Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
Pavel Boldyrev 2025-07-14 21:14:40 -04:00 committed by GitHub
parent 09e3cd62b7
commit 2c3f0c5578
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 29 additions and 6 deletions

View File

@ -334,12 +334,23 @@ func validateResponseCode(res *http.Response) error {
errRes := &ErrorResponseBody{} errRes := &ErrorResponseBody{}
err := json.NewDecoder(res.Body).Decode(errRes) err := json.NewDecoder(res.Body).Decode(errRes)
if err == nil && errRes.Errors != nil { if err == nil {
var errList []string var errList []string
if errRes.Errors != nil {
for k, v := range *errRes.Errors { for k, v := range *errRes.Errors {
errList = append(errList, fmt.Sprintf("%s: %s", k, strings.TrimRight(v, "\n\r"))) errList = append(errList, fmt.Sprintf("%s: %s", k, strings.TrimRight(v, "\n\r")))
} }
}
if errRes.Message != nil && *errRes.Message != "" {
split := slices.Compact(strings.Split(*errRes.Message, "\n"))
// skip empty lines and the first line, which is a duplicate of the HTTP status message
split = slices.DeleteFunc(split, func(s string) bool {
return len(s) == 0 || strings.HasPrefix(s, msg)
})
errList = append(errList, split...)
}
msg = fmt.Sprintf("%s (%s)", msg, strings.Join(errList, " - ")) msg = fmt.Sprintf("%s (%s)", msg, strings.Join(errList, " - "))
} }

View File

@ -9,6 +9,7 @@ package api
import ( import (
"context" "context"
"errors" "errors"
"io"
"net/http" "net/http"
"reflect" "reflect"
"strconv" "strconv"
@ -53,6 +54,7 @@ func TestClientDoRequest(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
status string status string
body string
wantErr error wantErr error
}{ }{
{name: "no error", status: "200 OK", wantErr: nil}, {name: "no error", status: "200 OK", wantErr: nil},
@ -62,6 +64,15 @@ func TestClientDoRequest(t *testing.T) {
Code: 500, Code: 500,
Message: "Internal Server Error", Message: "Internal Server Error",
}}, }},
{
name: "500 status with body",
status: "500 create sdn zone object failed: 400 Parameter verification failed.",
body: `{"message":"create sdn zone object failed: 400 Parameter verification failed.\nipam: ipam-simple not existing\n","data":null}`,
wantErr: &HTTPError{
Code: 500,
Message: "create sdn zone object failed: 400 Parameter verification failed. (ipam: ipam-simple not existing)",
},
},
} }
for _, tt := range tests { for _, tt := range tests {
@ -77,7 +88,7 @@ func TestClientDoRequest(t *testing.T) {
return &http.Response{ return &http.Response{
Status: tt.status, Status: tt.status,
StatusCode: sc, StatusCode: sc,
Body: nil, Body: io.NopCloser(strings.NewReader(tt.body)),
} }
}), }),
}, },

View File

@ -21,6 +21,7 @@ type MultiPartData struct {
// ErrorResponseBody contains the body of an error response. // ErrorResponseBody contains the body of an error response.
type ErrorResponseBody struct { type ErrorResponseBody struct {
Data *string `json:"data"` Data *string `json:"data"`
Message *string `json:"message"`
Errors *map[string]string `json:"errors"` Errors *map[string]string `json:"errors"`
} }