diff --git a/api/admin/accounts.go b/api/admin/accounts.go index 37db22e..7cc2ccc 100644 --- a/api/admin/accounts.go +++ b/api/admin/accounts.go @@ -120,7 +120,7 @@ func (rs *AccountResource) create(w http.ResponseWriter, r *http.Request) { if err := rs.Store.Create(data.Account); err != nil { switch err.(type) { case validation.Errors: - render.Render(w, r, ErrValidation(ErrAccountValidation, err)) + render.Render(w, r, ErrValidation(ErrAccountValidation, err.(validation.Errors))) return } render.Render(w, r, ErrInvalidRequest(err)) @@ -145,7 +145,7 @@ func (rs *AccountResource) update(w http.ResponseWriter, r *http.Request) { if err := rs.Store.Update(acc); err != nil { switch err.(type) { case validation.Errors: - render.Render(w, r, ErrValidation(ErrAccountValidation, err)) + render.Render(w, r, ErrValidation(ErrAccountValidation, err.(validation.Errors))) return } render.Render(w, r, ErrInvalidRequest(err)) diff --git a/api/admin/errors.go b/api/admin/errors.go index d239dc8..a713ce8 100644 --- a/api/admin/errors.go +++ b/api/admin/errors.go @@ -1,10 +1,10 @@ package admin import ( - "encoding/json" "net/http" "github.com/go-chi/render" + validation "github.com/go-ozzo/ozzo-validation" ) // ErrResponse renderer type for handling all sorts of errors. @@ -12,9 +12,10 @@ type ErrResponse struct { Err error `json:"-"` // low-level runtime error HTTPStatusCode int `json:"-"` // http response status code - StatusText string `json:"status"` // user-level status message - AppCode int64 `json:"code,omitempty"` // application-specific error code - ErrorText string `json:"error,omitempty"` // application-level error message, for debugging + StatusText string `json:"status"` // user-level status message + AppCode int64 `json:"code,omitempty"` // application-specific error code + ErrorText string `json:"error,omitempty"` // application-level error message, for debugging + ValidationErrors validation.Errors `json:"errors,omitempty"` // user level model validation errors } // Render sets the application-specific error code in AppCode. @@ -43,29 +44,14 @@ func ErrRender(err error) render.Renderer { } } -// ErrValidationResponse renderer for handling validation errors. -type ErrValidationResponse struct { - *ErrResponse - Errors string `json:"errors,omitempty"` -} - -// Render sets the application-specific error code in AppCode. -func (ev *ErrValidationResponse) Render(w http.ResponseWriter, r *http.Request) error { - render.Status(r, ev.ErrResponse.HTTPStatusCode) - return nil -} - // ErrValidation returns status 422 Unprocessable Entity stating validation errors. -func ErrValidation(err error, valErrors error) render.Renderer { - b, _ := json.Marshal(valErrors) - return &ErrValidationResponse{ - &ErrResponse{ - Err: err, - HTTPStatusCode: http.StatusUnprocessableEntity, - StatusText: http.StatusText(http.StatusUnprocessableEntity), - ErrorText: err.Error(), - }, - string(b), +func ErrValidation(err error, valErr validation.Errors) render.Renderer { + return &ErrResponse{ + Err: err, + HTTPStatusCode: http.StatusUnprocessableEntity, + StatusText: http.StatusText(http.StatusUnprocessableEntity), + ErrorText: err.Error(), + ValidationErrors: valErr, } } diff --git a/api/app/account.go b/api/app/account.go index e76e5de..039a11e 100644 --- a/api/app/account.go +++ b/api/app/account.go @@ -2,6 +2,7 @@ package app import ( "context" + "errors" "net/http" "strconv" "strings" @@ -14,6 +15,11 @@ import ( "github.com/dhax/go-base/auth/pwdless" ) +// The list of error types returned from account resource. +var ( + ErrAccountValidation = errors.New("account validation error") +) + // AccountStore defines database operations for account. type AccountStore interface { Get(id int) (*pwdless.Account, error) @@ -103,7 +109,7 @@ func (rs *AccountResource) update(w http.ResponseWriter, r *http.Request) { if err := rs.Store.Update(acc); err != nil { switch err.(type) { case validation.Errors: - render.Render(w, r, ErrValidation(err)) + render.Render(w, r, ErrValidation(ErrAccountValidation, err.(validation.Errors))) return } render.Render(w, r, ErrRender(err)) diff --git a/api/app/errors.go b/api/app/errors.go index 55ab726..e274d17 100644 --- a/api/app/errors.go +++ b/api/app/errors.go @@ -1,10 +1,10 @@ package app import ( - "encoding/json" "net/http" "github.com/go-chi/render" + validation "github.com/go-ozzo/ozzo-validation" ) // ErrResponse renderer type for handling all sorts of errors. @@ -12,9 +12,10 @@ type ErrResponse struct { Err error `json:"-"` // low-level runtime error HTTPStatusCode int `json:"-"` // http response status code - StatusText string `json:"status"` // user-level status message - AppCode int64 `json:"code,omitempty"` // application-specific error code - ErrorText string `json:"error,omitempty"` // application-level error message, for debugging + StatusText string `json:"status"` // user-level status message + AppCode int64 `json:"code,omitempty"` // application-specific error code + ErrorText string `json:"error,omitempty"` // application-level error message, for debugging + ValidationErrors validation.Errors `json:"errors,omitempty"` // user level model validation errors } // Render sets the application-specific error code in AppCode. @@ -33,29 +34,14 @@ func ErrInvalidRequest(err error) render.Renderer { } } -// ErrValidationResponse renderer for handling validation errors. -type ErrValidationResponse struct { - *ErrResponse - Errors string `json:"errors,omitempty"` -} - -// Render sets the application-specific error code in AppCode. -func (ev *ErrValidationResponse) Render(w http.ResponseWriter, r *http.Request) error { - render.Status(r, ev.ErrResponse.HTTPStatusCode) - return nil -} - // ErrValidation returns status 422 Unprocessable Entity stating validation errors. -func ErrValidation(valErrors error) render.Renderer { - b, _ := json.Marshal(valErrors) - return &ErrValidationResponse{ - &ErrResponse{ - Err: nil, - HTTPStatusCode: http.StatusUnprocessableEntity, - StatusText: http.StatusText(http.StatusUnprocessableEntity), - ErrorText: "object validation error", - }, - string(b), +func ErrValidation(err error, valErr validation.Errors) render.Renderer { + return &ErrResponse{ + Err: err, + HTTPStatusCode: http.StatusUnprocessableEntity, + StatusText: http.StatusText(http.StatusUnprocessableEntity), + ErrorText: err.Error(), + ValidationErrors: valErr, } } diff --git a/api/app/profile.go b/api/app/profile.go index 3744efa..26acf2e 100644 --- a/api/app/profile.go +++ b/api/app/profile.go @@ -2,6 +2,7 @@ package app import ( "context" + "errors" "net/http" "github.com/dhax/go-base/auth/jwt" @@ -11,6 +12,11 @@ import ( validation "github.com/go-ozzo/ozzo-validation" ) +// The list of error types returned from account resource. +var ( + ErrProfileValidation = errors.New("profile validation error") +) + // ProfileStore defines database operations for a profile. type ProfileStore interface { Get(accountID int) (*models.Profile, error) @@ -85,7 +91,7 @@ func (rs *ProfileResource) update(w http.ResponseWriter, r *http.Request) { if err := rs.Store.Update(p); err != nil { switch err.(type) { case validation.Errors: - render.Render(w, r, ErrValidation(err)) + render.Render(w, r, ErrValidation(ErrProfileValidation, err.(validation.Errors))) return } render.Render(w, r, ErrRender(err))