Rename package srverrors to httperror

- Package names are preferred to be in singular form¹.
- Since errors are just for HTTP and not generic, I changed the base name to
'http'.
- I didn't name it simply 'error', because it would then conflict with the
- standard 'error' interface.

¹: https://rakyll.org/style-packages/
This commit is contained in:
pancho horrillo
2019-11-20 07:49:38 +01:00
parent 0d66fe9963
commit 206aac5747
9 changed files with 77 additions and 77 deletions
+2 -2
View File
@@ -22,7 +22,7 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"github.com/BBVA/kapow/internal/server/srverrors" "github.com/BBVA/kapow/internal/server/httperror"
) )
// Reason returns the reason phrase embedded within the JSON error // Reason returns the reason phrase embedded within the JSON error
@@ -33,7 +33,7 @@ func Reason(r *http.Response) (string, error) {
return "", errors.New("error reading response's body") return "", errors.New("error reading response's body")
} }
reason := &srverrors.ServerErrMessage{} reason := &httperror.ServerErrMessage{}
err = json.Unmarshal(body, reason) err = json.Unmarshal(body, reason)
if err != nil { if err != nil {
return "", errors.New("error unmarshaling JSON") return "", errors.New("error unmarshaling JSON")
+8 -8
View File
@@ -24,8 +24,8 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/BBVA/kapow/internal/server/httperror"
"github.com/BBVA/kapow/internal/server/model" "github.com/BBVA/kapow/internal/server/model"
"github.com/BBVA/kapow/internal/server/srverrors"
"github.com/BBVA/kapow/internal/server/user" "github.com/BBVA/kapow/internal/server/user"
) )
@@ -53,7 +53,7 @@ func removeRoute(res http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req) vars := mux.Vars(req)
id := vars["id"] id := vars["id"]
if err := funcRemove(id); err != nil { if err := funcRemove(id); err != nil {
srverrors.ErrorJSON(res, "Route Not Found", http.StatusNotFound) httperror.ErrorJSON(res, "Route Not Found", http.StatusNotFound)
return return
} }
@@ -94,29 +94,29 @@ func addRoute(res http.ResponseWriter, req *http.Request) {
payload, _ := ioutil.ReadAll(req.Body) payload, _ := ioutil.ReadAll(req.Body)
err := json.Unmarshal(payload, &route) err := json.Unmarshal(payload, &route)
if err != nil { if err != nil {
srverrors.ErrorJSON(res, "Malformed JSON", http.StatusBadRequest) httperror.ErrorJSON(res, "Malformed JSON", http.StatusBadRequest)
return return
} }
if route.Method == "" { if route.Method == "" {
srverrors.ErrorJSON(res, "Invalid Route", http.StatusUnprocessableEntity) httperror.ErrorJSON(res, "Invalid Route", http.StatusUnprocessableEntity)
return return
} }
if route.Pattern == "" { if route.Pattern == "" {
srverrors.ErrorJSON(res, "Invalid Route", http.StatusUnprocessableEntity) httperror.ErrorJSON(res, "Invalid Route", http.StatusUnprocessableEntity)
return return
} }
err = pathValidator(route.Pattern) err = pathValidator(route.Pattern)
if err != nil { if err != nil {
srverrors.ErrorJSON(res, "Invalid Route", http.StatusUnprocessableEntity) httperror.ErrorJSON(res, "Invalid Route", http.StatusUnprocessableEntity)
return return
} }
id, err := idGenerator() id, err := idGenerator()
if err != nil { if err != nil {
srverrors.ErrorJSON(res, "Internal Server Error", http.StatusInternalServerError) httperror.ErrorJSON(res, "Internal Server Error", http.StatusInternalServerError)
return return
} }
@@ -138,7 +138,7 @@ var funcGet func(string) (model.Route, error) = user.Routes.Get
func getRoute(res http.ResponseWriter, req *http.Request) { func getRoute(res http.ResponseWriter, req *http.Request) {
id := mux.Vars(req)["id"] id := mux.Vars(req)["id"]
if r, err := funcGet(id); err != nil { if r, err := funcGet(id); err != nil {
srverrors.ErrorJSON(res, "Route Not Found", http.StatusNotFound) httperror.ErrorJSON(res, "Route Not Found", http.StatusNotFound)
} else { } else {
res.Header().Set("Content-Type", "application/json") res.Header().Set("Content-Type", "application/json")
rBytes, _ := json.Marshal(r) rBytes, _ := json.Marshal(r)
+38 -38
View File
@@ -30,8 +30,8 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/BBVA/kapow/internal/server/httperror"
"github.com/BBVA/kapow/internal/server/model" "github.com/BBVA/kapow/internal/server/model"
"github.com/BBVA/kapow/internal/server/srverrors"
"github.com/BBVA/kapow/internal/server/user" "github.com/BBVA/kapow/internal/server/user"
) )
@@ -46,7 +46,7 @@ func checkErrorResponse(r *http.Response, expectedErrcode int, expectedReason st
errList = append(errList, fmt.Errorf("Content-Type header mismatch. Expected: %q, got: %q", "application/json; charset=utf-8", v)) errList = append(errList, fmt.Errorf("Content-Type header mismatch. Expected: %q, got: %q", "application/json; charset=utf-8", v))
} }
errMsg := srverrors.ServerErrMessage{} errMsg := httperror.ServerErrMessage{}
if bodyBytes, err := ioutil.ReadAll(r.Body); err != nil { if bodyBytes, err := ioutil.ReadAll(r.Body); err != nil {
errList = append(errList, fmt.Errorf("Unexpected error reading response body: %v", err)) errList = append(errList, fmt.Errorf("Unexpected error reading response body: %v", err))
} else if err := json.Unmarshal(bodyBytes, &errMsg); err != nil { } else if err := json.Unmarshal(bodyBytes, &errMsg); err != nil {
@@ -118,10 +118,10 @@ func TestPathValidatorErrorWhenInvalidPath(t *testing.T) {
func TestAddRouteReturnsBadRequestWhenMalformedJSONBody(t *testing.T) { func TestAddRouteReturnsBadRequestWhenMalformedJSONBody(t *testing.T) {
reqPayload := `{ reqPayload := `{
method": "GET", method": "GET",
url_pattern": "/hello", url_pattern": "/hello",
entrypoint": null, entrypoint": null,
command": "echo Hello World | kapow set /response/body" command": "echo Hello World | kapow set /response/body"
}` }`
req := httptest.NewRequest(http.MethodPost, "/routes", strings.NewReader(reqPayload)) req := httptest.NewRequest(http.MethodPost, "/routes", strings.NewReader(reqPayload))
@@ -141,46 +141,46 @@ func TestAddRouteReturns422ErrorWhenMandatoryFieldsMissing(t *testing.T) {
}{ }{
{`{}`, "EmptyBody", true}, {`{}`, "EmptyBody", true},
{`{ {`{
"method": "GET" "method": "GET"
}`, }`,
"Missing url_pattern", "Missing url_pattern",
true, true,
}, },
{`{ {`{
"url_pattern": "/hello" "url_pattern": "/hello"
}`, }`,
"Missing method", "Missing method",
true, true,
}, },
{`{ {`{
"method": "GET", "method": "GET",
"url_pattern": "/hello" "url_pattern": "/hello"
}`, }`,
"", "",
false, false,
}, },
{`{ {`{
"method": "GET", "method": "GET",
"url_pattern": "/hello", "url_pattern": "/hello",
"entrypoint": "" "entrypoint": ""
}`, }`,
"", "",
false, false,
}, },
{`{ {`{
"method": "GET", "method": "GET",
"url_pattern": "/hello", "url_pattern": "/hello",
"command": "" "command": ""
}`, }`,
"", "",
false, false,
}, },
{`{ {`{
"method": "GET", "method": "GET",
"url_pattern": "/hello", "url_pattern": "/hello",
"entrypoint": "", "entrypoint": "",
"command": "" "command": ""
}`, }`,
"", "",
false, false,
}, },
@@ -210,10 +210,10 @@ func TestAddRouteReturns422ErrorWhenMandatoryFieldsMissing(t *testing.T) {
func TestAddRouteGeneratesRouteID(t *testing.T) { func TestAddRouteGeneratesRouteID(t *testing.T) {
reqPayload := `{ reqPayload := `{
"method": "GET", "method": "GET",
"url_pattern": "/hello", "url_pattern": "/hello",
"entrypoint": "/bin/sh -c", "entrypoint": "/bin/sh -c",
"command": "echo Hello World | kapow set /response/body" "command": "echo Hello World | kapow set /response/body"
}` }`
req := httptest.NewRequest(http.MethodPost, "/routes", strings.NewReader(reqPayload)) req := httptest.NewRequest(http.MethodPost, "/routes", strings.NewReader(reqPayload))
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
@@ -236,10 +236,10 @@ func TestAddRouteGeneratesRouteID(t *testing.T) {
func TestAddRoute500sWhenIDGeneratorFails(t *testing.T) { func TestAddRoute500sWhenIDGeneratorFails(t *testing.T) {
reqPayload := `{ reqPayload := `{
"method": "GET", "method": "GET",
"url_pattern": "/hello", "url_pattern": "/hello",
"entrypoint": "/bin/sh -c", "entrypoint": "/bin/sh -c",
"command": "echo Hello World | kapow set /response/body" "command": "echo Hello World | kapow set /response/body"
}` }`
req := httptest.NewRequest(http.MethodPost, "/routes", strings.NewReader(reqPayload)) req := httptest.NewRequest(http.MethodPost, "/routes", strings.NewReader(reqPayload))
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
@@ -264,10 +264,10 @@ func TestAddRoute500sWhenIDGeneratorFails(t *testing.T) {
func TestAddRouteReturnsCreated(t *testing.T) { func TestAddRouteReturnsCreated(t *testing.T) {
reqPayload := `{ reqPayload := `{
"method": "GET", "method": "GET",
"url_pattern": "/hello", "url_pattern": "/hello",
"entrypoint": "/bin/sh -c", "entrypoint": "/bin/sh -c",
"command": "echo Hello World | kapow set /response/body" "command": "echo Hello World | kapow set /response/body"
}` }`
req := httptest.NewRequest(http.MethodPost, "/routes", strings.NewReader(reqPayload)) req := httptest.NewRequest(http.MethodPost, "/routes", strings.NewReader(reqPayload))
+2 -2
View File
@@ -19,8 +19,8 @@ package data
import ( import (
"net/http" "net/http"
"github.com/BBVA/kapow/internal/server/httperror"
"github.com/BBVA/kapow/internal/server/model" "github.com/BBVA/kapow/internal/server/model"
"github.com/BBVA/kapow/internal/server/srverrors"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
@@ -40,7 +40,7 @@ func checkHandler(fn resourceHandler) func(http.ResponseWriter, *http.Request) {
if h, ok := Handlers.Get(handlerID); ok { if h, ok := Handlers.Get(handlerID); ok {
fn(w, r, h) fn(w, r, h)
} else { } else {
srverrors.ErrorJSON(w, "Handler ID Not Found", http.StatusNotFound) httperror.ErrorJSON(w, "Handler ID Not Found", http.StatusNotFound)
} }
} }
} }
+16 -16
View File
@@ -23,8 +23,8 @@ import (
"net/textproto" "net/textproto"
"strconv" "strconv"
"github.com/BBVA/kapow/internal/server/httperror"
"github.com/BBVA/kapow/internal/server/model" "github.com/BBVA/kapow/internal/server/model"
"github.com/BBVA/kapow/internal/server/srverrors"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
@@ -40,7 +40,7 @@ func getRequestBody(w http.ResponseWriter, r *http.Request, h *model.Handler) {
n, err := io.Copy(w, h.Request.Body) n, err := io.Copy(w, h.Request.Body)
if err != nil { if err != nil {
if n == 0 { if n == 0 {
srverrors.ErrorJSON(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) httperror.ErrorJSON(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
} else { } else {
// Only way to abort current connection as of go 1.13 // Only way to abort current connection as of go 1.13
// https://github.com/golang/go/issues/16542 // https://github.com/golang/go/issues/16542
@@ -72,7 +72,7 @@ func getRequestMatches(w http.ResponseWriter, r *http.Request, h *model.Handler)
if value, ok := vars[name]; ok { if value, ok := vars[name]; ok {
_, _ = w.Write([]byte(value)) _, _ = w.Write([]byte(value))
} else { } else {
srverrors.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound) httperror.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound)
} }
} }
@@ -82,7 +82,7 @@ func getRequestParams(w http.ResponseWriter, r *http.Request, h *model.Handler)
if values, ok := h.Request.URL.Query()[name]; ok { if values, ok := h.Request.URL.Query()[name]; ok {
_, _ = w.Write([]byte(values[0])) _, _ = w.Write([]byte(values[0]))
} else { } else {
srverrors.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound) httperror.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound)
} }
} }
@@ -92,7 +92,7 @@ func getRequestHeaders(w http.ResponseWriter, r *http.Request, h *model.Handler)
if values, ok := h.Request.Header[textproto.CanonicalMIMEHeaderKey(name)]; ok { if values, ok := h.Request.Header[textproto.CanonicalMIMEHeaderKey(name)]; ok {
_, _ = w.Write([]byte(values[0])) _, _ = w.Write([]byte(values[0]))
} else { } else {
srverrors.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound) httperror.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound)
} }
} }
@@ -102,7 +102,7 @@ func getRequestCookies(w http.ResponseWriter, r *http.Request, h *model.Handler)
if cookie, err := h.Request.Cookie(name); err == nil { if cookie, err := h.Request.Cookie(name); err == nil {
_, _ = w.Write([]byte(cookie.Value)) _, _ = w.Write([]byte(cookie.Value))
} else { } else {
srverrors.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound) httperror.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound)
} }
} }
@@ -118,11 +118,11 @@ func getRequestForm(w http.ResponseWriter, r *http.Request, h *model.Handler) {
// We tried to exercise this execution path but didn't know how. // We tried to exercise this execution path but didn't know how.
err := h.Request.ParseForm() err := h.Request.ParseForm()
if err != nil { if err != nil {
srverrors.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound) httperror.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound)
} else if values, ok := h.Request.Form[name]; ok { } else if values, ok := h.Request.Form[name]; ok {
_, _ = w.Write([]byte(values[0])) _, _ = w.Write([]byte(values[0]))
} else { } else {
srverrors.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound) httperror.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound)
} }
} }
@@ -133,7 +133,7 @@ func getRequestFileName(w http.ResponseWriter, r *http.Request, h *model.Handler
if err == nil { if err == nil {
_, _ = w.Write([]byte(header.Filename)) _, _ = w.Write([]byte(header.Filename))
} else { } else {
srverrors.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound) httperror.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound)
} }
} }
@@ -144,7 +144,7 @@ func getRequestFileContent(w http.ResponseWriter, r *http.Request, h *model.Hand
if err == nil { if err == nil {
_, _ = io.Copy(w, file) _, _ = io.Copy(w, file)
} else { } else {
srverrors.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound) httperror.ErrorJSON(w, ResourceItemNotFound, http.StatusNotFound)
} }
} }
@@ -153,14 +153,14 @@ func getRequestFileContent(w http.ResponseWriter, r *http.Request, h *model.Hand
func setResponseStatus(w http.ResponseWriter, r *http.Request, h *model.Handler) { func setResponseStatus(w http.ResponseWriter, r *http.Request, h *model.Handler) {
sb, err := ioutil.ReadAll(r.Body) sb, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
srverrors.ErrorJSON(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) httperror.ErrorJSON(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return return
} }
if si, err := strconv.Atoi(string(sb)); err != nil { if si, err := strconv.Atoi(string(sb)); err != nil {
srverrors.ErrorJSON(w, NonIntegerValue, http.StatusUnprocessableEntity) httperror.ErrorJSON(w, NonIntegerValue, http.StatusUnprocessableEntity)
} else if http.StatusText(si) == "" { } else if http.StatusText(si) == "" {
srverrors.ErrorJSON(w, InvalidStatusCode, http.StatusBadRequest) httperror.ErrorJSON(w, InvalidStatusCode, http.StatusBadRequest)
} else { } else {
h.Writer.WriteHeader(int(si)) h.Writer.WriteHeader(int(si))
} }
@@ -170,7 +170,7 @@ func setResponseHeaders(w http.ResponseWriter, r *http.Request, h *model.Handler
name := mux.Vars(r)["name"] name := mux.Vars(r)["name"]
vb, err := ioutil.ReadAll(r.Body) vb, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
srverrors.ErrorJSON(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) httperror.ErrorJSON(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return return
} }
@@ -186,7 +186,7 @@ func setResponseCookies(w http.ResponseWriter, r *http.Request, h *model.Handler
name := mux.Vars(r)["name"] name := mux.Vars(r)["name"]
vb, err := ioutil.ReadAll(r.Body) vb, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
srverrors.ErrorJSON(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) httperror.ErrorJSON(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return return
} }
@@ -199,6 +199,6 @@ func setResponseBody(w http.ResponseWriter, r *http.Request, h *model.Handler) {
if n > 0 { if n > 0 {
panic("Truncated body") panic("Truncated body")
} }
srverrors.ErrorJSON(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) httperror.ErrorJSON(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
} }
} }
+2 -2
View File
@@ -20,7 +20,7 @@ import (
"log" "log"
"net/http" "net/http"
"github.com/BBVA/kapow/internal/server/srverrors" "github.com/BBVA/kapow/internal/server/httperror"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
@@ -38,7 +38,7 @@ func configRouter(rs []routeSpec) (r *mux.Router) {
r.HandleFunc( r.HandleFunc(
"/handlers/{handlerID}/{resource:.*}", "/handlers/{handlerID}/{resource:.*}",
func(w http.ResponseWriter, r *http.Request) { func(w http.ResponseWriter, r *http.Request) {
srverrors.ErrorJSON(w, "Invalid Resource Path", http.StatusBadRequest) httperror.ErrorJSON(w, "Invalid Resource Path", http.StatusBadRequest)
}) })
return r return r
} }
+2 -2
View File
@@ -24,8 +24,8 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/BBVA/kapow/internal/server/httperror"
"github.com/BBVA/kapow/internal/server/model" "github.com/BBVA/kapow/internal/server/model"
"github.com/BBVA/kapow/internal/server/srverrors"
) )
func checkErrorResponse(r *http.Response, expectedErrcode int, expectedReason string) []error { func checkErrorResponse(r *http.Response, expectedErrcode int, expectedReason string) []error {
@@ -39,7 +39,7 @@ func checkErrorResponse(r *http.Response, expectedErrcode int, expectedReason st
errList = append(errList, fmt.Errorf("Content-Type header mismatch. Expected: %q, got: %q", "application/json; charset=utf-8", v)) errList = append(errList, fmt.Errorf("Content-Type header mismatch. Expected: %q, got: %q", "application/json; charset=utf-8", v))
} }
errMsg := srverrors.ServerErrMessage{} errMsg := httperror.ServerErrMessage{}
if bodyBytes, err := ioutil.ReadAll(r.Body); err != nil { if bodyBytes, err := ioutil.ReadAll(r.Body); err != nil {
errList = append(errList, fmt.Errorf("Unexpected error reading response body: %v", err)) errList = append(errList, fmt.Errorf("Unexpected error reading response body: %v", err))
} else if err := json.Unmarshal(bodyBytes, &errMsg); err != nil { } else if err := json.Unmarshal(bodyBytes, &errMsg); err != nil {
@@ -1,4 +1,4 @@
package srverrors package httperror
import ( import (
"encoding/json" "encoding/json"
@@ -1,4 +1,4 @@
package srverrors_test package httperror_test
import ( import (
"encoding/json" "encoding/json"
@@ -7,13 +7,13 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/BBVA/kapow/internal/server/srverrors" "github.com/BBVA/kapow/internal/server/httperror"
) )
func TestErrorJSONSetsAppJsonContentType(t *testing.T) { func TestErrorJSONSetsAppJsonContentType(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
srverrors.ErrorJSON(w, "Not Important Here", 0) httperror.ErrorJSON(w, "Not Important Here", 0)
if v := w.Result().Header.Get("Content-Type"); v != "application/json; charset=utf-8" { if v := w.Result().Header.Get("Content-Type"); v != "application/json; charset=utf-8" {
t.Errorf("Content-Type header mismatch. Expected: %q, got: %q", "application/json; charset=utf-8", v) t.Errorf("Content-Type header mismatch. Expected: %q, got: %q", "application/json; charset=utf-8", v)
@@ -23,7 +23,7 @@ func TestErrorJSONSetsAppJsonContentType(t *testing.T) {
func TestErrorJSONSetsRequestedStatusCode(t *testing.T) { func TestErrorJSONSetsRequestedStatusCode(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
srverrors.ErrorJSON(w, "Not Important Here", http.StatusGone) httperror.ErrorJSON(w, "Not Important Here", http.StatusGone)
if v := w.Result().StatusCode; v != http.StatusGone { if v := w.Result().StatusCode; v != http.StatusGone {
t.Errorf("Status code mismatch. Expected: %d, got: %d", http.StatusGone, v) t.Errorf("Status code mismatch. Expected: %d, got: %d", http.StatusGone, v)
@@ -34,9 +34,9 @@ func TestErrorJSONSetsBodyCorrectly(t *testing.T) {
expectedReason := "Something Not Found" expectedReason := "Something Not Found"
w := httptest.NewRecorder() w := httptest.NewRecorder()
srverrors.ErrorJSON(w, expectedReason, http.StatusNotFound) httperror.ErrorJSON(w, expectedReason, http.StatusNotFound)
errMsg := srverrors.ServerErrMessage{} errMsg := httperror.ServerErrMessage{}
if bodyBytes, err := ioutil.ReadAll(w.Result().Body); err != nil { if bodyBytes, err := ioutil.ReadAll(w.Result().Body); err != nil {
t.Errorf("Unexpected error reading response body: %v", err) t.Errorf("Unexpected error reading response body: %v", err)
} else if err := json.Unmarshal(bodyBytes, &errMsg); err != nil { } else if err := json.Unmarshal(bodyBytes, &errMsg); err != nil {