Repository: go-resty/resty (go)

Issue:
parseResponseBody overrides original error code in case of unmarshalling error
If the client has an `Error` object for automatic unmarshalling for the request, and the JSON response cannot be unmarshalled, the current behavior is to override the HTTP response status with a marshalling error like `unexpected end of JSON input`.

Since we cannot lose this information, I suggest to change:
```
                        if res.Request.Error != nil {
                              err = Unmarshalc(c, ct, res.body, res.Request.Error)
                        }

```
to:
```
                        if res.Request.Error != nil {
                              unmarshalErr := Unmarshalc(c, ct, res.body, res.Request.Error)
                              if unmarshalErr != nil {
                                      log.Printf("Failed to unmarshal response body: %s", unmarshalErr)
                              }
                        }
```
This way we'll miss the unmarshalling error but at least we can handle the server response status.

Maybe there's a better way to report the error, but I haven't found anyone ATM, please suggest an alternative if any. 

Pull request description:
fix: parseResponseBody overrides original error code in case of unmar…
This closes #673

I'm not sure what is the best practice to notify of the swallowed marshalling error, anyway I think we cannot override the original error received from the server because of that. Please let me know your feedback about this fix.

**Note**: I found this issue while using [gocloak](https://github.com/Nerzal/gocloak) the go client for Keycloak. Un fact, the latest versions of Keycloak have changed the response data for the 404/Not Found responses, and the body is empty instead of containing a JSON document, so the get requests fail with this `unexpected end of JSON input` error hiding the 404 status code, which is not acceptable.

Patch:
diff --git a/middleware.go b/middleware.go
index 6f866be..9b19c46 100644
--- a/middleware.go
+++ b/middleware.go
@@ -357,7 +357,10 @@ func parseResponseBody(c *Client, res *Response) (err error) {
 			}
 
 			if res.Request.Error != nil {
-				err = Unmarshalc(c, ct, res.body, res.Request.Error)
+				unmarshalErr := Unmarshalc(c, ct, res.body, res.Request.Error)
+				if unmarshalErr != nil {
+					c.log.Warnf("Cannot unmarshal response body: %s", unmarshalErr)
+				}
 			}
 		}
 	}


Test patch:
diff --git a/request_test.go b/request_test.go
index a385097..e2fcdd9 100644
--- a/request_test.go
+++ b/request_test.go
@@ -1744,6 +1744,54 @@ func TestHostHeaderOverride(t *testing.T) {
 	logResponse(t, resp)
 }
 
+type HTTPErrorResponse struct {
+	Error string `json:"error,omitempty"`
+}
+
+func TestNotFoundWithError(t *testing.T) {
+	var httpError HTTPErrorResponse
+	ts := createGetServer(t)
+	defer ts.Close()
+
+	resp, err := dc().R().
+		SetHeader(hdrContentTypeKey, "application/json").
+		SetError(&httpError).
+		Get(ts.URL + "/not-found-with-error")
+
+	assertError(t, err)
+	assertEqual(t, http.StatusNotFound, resp.StatusCode())
+	assertEqual(t, "404 Not Found", resp.Status())
+	assertNotNil(t, resp.Body())
+	assertEqual(t, "{\"error\": \"Not found\"}", resp.String())
+	assertNotNil(t, httpError)
+	assertEqual(t, "Not found", httpError.Error)
+
+	logResponse(t, resp)
+}
+
+func TestNotFoundWithoutError(t *testing.T) {
+	var httpError HTTPErrorResponse
+
+	ts := createGetServer(t)
+	defer ts.Close()
+
+	c := dc().outputLogTo(os.Stdout)
+	resp, err := c.R().
+		SetError(&httpError).
+		SetHeader(hdrContentTypeKey, "application/json").
+		Get(ts.URL + "/not-found-no-error")
+
+	assertError(t, err)
+	assertEqual(t, http.StatusNotFound, resp.StatusCode())
+	assertEqual(t, "404 Not Found", resp.Status())
+	assertNotNil(t, resp.Body())
+	assertEqual(t, 0, len(resp.Body()))
+	assertNotNil(t, httpError)
+	assertEqual(t, "", httpError.Error)
+
+	logResponse(t, resp)
+}
+
 func TestPathParamURLInput(t *testing.T) {
 	ts := createGetServer(t)
 	defer ts.Close()
diff --git a/resty_test.go b/resty_test.go
index 76d56fd..5fe41a9 100644
--- a/resty_test.go
+++ b/resty_test.go
@@ -113,6 +113,13 @@ func createGetServer(t *testing.T) *httptest.Server {
 				_, _ = w.Write(body)
 			case "/host-header":
 				_, _ = w.Write([]byte(r.Host))
+			case "/not-found-with-error":
+				w.Header().Set(hdrContentTypeKey, "application/json")
+				w.WriteHeader(http.StatusNotFound)
+				_, _ = w.Write([]byte(`{"error": "Not found"}`))
+			case "/not-found-no-error":
+				w.Header().Set(hdrContentTypeKey, "application/json")
+				w.WriteHeader(http.StatusNotFound)
 			}
 
 			switch {