mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 08:58:41 +00:00
always return errors to the client as a map slice (#724)
keep the format for error returns consistent by always returning a []map[string]string for json errors. This simplifies the error handling on the frontend. Use "name":"base" as the name field for errors which do not have a specific or known form field.
This commit is contained in:
parent
a13042e11b
commit
6cb1026d86
2 changed files with 27 additions and 12 deletions
|
|
@ -92,16 +92,16 @@ func TestLogin(t *testing.T) {
|
|||
|
||||
requestBody := &nopCloser{bytes.NewBuffer(j)}
|
||||
resp, err := http.Post(server.URL+"/api/v1/kolide/login", "application/json", requestBody)
|
||||
assert.Nil(t, err)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, tt.status, resp.StatusCode)
|
||||
|
||||
var jsn = struct {
|
||||
User *kolide.User `json:"user"`
|
||||
Token string `json:"token"`
|
||||
Err string `json:"error,omitempty"`
|
||||
User *kolide.User `json:"user"`
|
||||
Token string `json:"token"`
|
||||
Err []map[string]string `json:"errors,omitempty"`
|
||||
}{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&jsn)
|
||||
assert.Nil(t, err)
|
||||
require.Nil(t, err)
|
||||
|
||||
if tt.status != http.StatusOK {
|
||||
assert.NotEqual(t, "", jsn.Err)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,16 @@ type errorer interface {
|
|||
type jsonError struct {
|
||||
Message string `json:"message"`
|
||||
Errors []map[string]string `json:"errors,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// use baseError to encode an jsonError.Errors field with an error that has
|
||||
// a generic "name" field. The frontend client always expects errors in a
|
||||
// []map[string]string format.
|
||||
func baseError(err string) []map[string]string {
|
||||
return []map[string]string{map[string]string{
|
||||
"name": "base",
|
||||
"reason": err},
|
||||
}
|
||||
}
|
||||
|
||||
// encode error and status header to the client
|
||||
|
|
@ -32,6 +41,7 @@ func encodeError(ctx context.Context, err error, w http.ResponseWriter) {
|
|||
enc.SetIndent("", " ")
|
||||
|
||||
type validationError interface {
|
||||
error
|
||||
Invalid() []map[string]string
|
||||
}
|
||||
if e, ok := err.(validationError); ok {
|
||||
|
|
@ -45,12 +55,13 @@ func encodeError(ctx context.Context, err error, w http.ResponseWriter) {
|
|||
}
|
||||
|
||||
type authenticationError interface {
|
||||
error
|
||||
AuthError() string
|
||||
}
|
||||
if e, ok := err.(authenticationError); ok {
|
||||
ae := jsonError{
|
||||
Message: "Authentication Failed",
|
||||
Error: e.AuthError(),
|
||||
Errors: baseError(e.AuthError()),
|
||||
}
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
enc.Encode(ae)
|
||||
|
|
@ -100,10 +111,11 @@ func encodeError(ctx context.Context, err error, w http.ResponseWriter) {
|
|||
if e, ok := err.(notFoundError); ok {
|
||||
je := jsonError{
|
||||
Message: "Resource Not Found",
|
||||
Error: e.Error(),
|
||||
Errors: baseError(e.Error()),
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
enc.Encode(je)
|
||||
return
|
||||
}
|
||||
|
||||
type existsError interface {
|
||||
|
|
@ -113,10 +125,11 @@ func encodeError(ctx context.Context, err error, w http.ResponseWriter) {
|
|||
if e, ok := err.(existsError); ok {
|
||||
je := jsonError{
|
||||
Message: "Resource Already Exists",
|
||||
Error: e.Error(),
|
||||
Errors: baseError(e.Error()),
|
||||
}
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
enc.Encode(je)
|
||||
return
|
||||
}
|
||||
|
||||
// Other errors
|
||||
|
|
@ -128,7 +141,9 @@ func encodeError(ctx context.Context, err error, w http.ResponseWriter) {
|
|||
default:
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
enc.Encode(map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
je := jsonError{
|
||||
Message: "Unknown Error",
|
||||
Errors: baseError(err.Error()),
|
||||
}
|
||||
enc.Encode(je)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue