diff --git a/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go index 00421a2..b0f99c6 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go @@ -42,7 +42,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() server.HandlerFunc { } - errs := make(server.ValidationErrors, 0) + errs := validate.NewFieldErrors() file, _, err := r.FormFile("file") if err != nil { @@ -62,7 +62,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() server.HandlerFunc { errs = errs.Append("name", "name is required") } - if errs.HasErrors() { + if !errs.Nil() { return server.Respond(w, http.StatusUnprocessableEntity, errs) } diff --git a/backend/internal/sys/validate/errors.go b/backend/internal/sys/validate/errors.go index b4fd58d..f2b85eb 100644 --- a/backend/internal/sys/validate/errors.go +++ b/backend/internal/sys/validate/errors.go @@ -51,6 +51,17 @@ type FieldError struct { // FieldErrors represents a collection of field errors. type FieldErrors []FieldError +func (fe FieldErrors) Append(field, reason string) FieldErrors { + return append(fe, FieldError{ + Field: field, + Error: reason, + }) +} + +func (fe FieldErrors) Nil() bool { + return len(fe) == 0 +} + // Error implments the error interface. func (fe FieldErrors) Error() string { d, err := json.Marshal(fe) diff --git a/backend/pkgs/server/middleware.go b/backend/pkgs/server/middleware.go index acbe869..f24f06b 100644 --- a/backend/pkgs/server/middleware.go +++ b/backend/pkgs/server/middleware.go @@ -26,6 +26,8 @@ func wrapMiddleware(mw []Middleware, handler Handler) Handler { } // StripTrailingSlash is a middleware that will strip trailing slashes from the request path. +// +// Example: /api/v1/ -> /api/v1 func StripTrailingSlash() Middleware { return func(h Handler) Handler { return HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { diff --git a/backend/pkgs/server/request.go b/backend/pkgs/server/request.go index ffb76d1..38c3189 100644 --- a/backend/pkgs/server/request.go +++ b/backend/pkgs/server/request.go @@ -16,7 +16,7 @@ func Decode(r *http.Request, val interface{}) error { return nil } -// GetId is a shotcut to get the id from the request URL or return a default value +// GetId is a shortcut to get the id from the request URL or return a default value func GetParam(r *http.Request, key, d string) string { val := r.URL.Query().Get(key) @@ -27,22 +27,22 @@ func GetParam(r *http.Request, key, d string) string { return val } -// GetSkip is a shotcut to get the skip from the request URL parameters +// GetSkip is a shortcut to get the skip from the request URL parameters func GetSkip(r *http.Request, d string) string { return GetParam(r, "skip", d) } -// GetSkip is a shotcut to get the skip from the request URL parameters +// GetSkip is a shortcut to get the skip from the request URL parameters func GetId(r *http.Request, d string) string { return GetParam(r, "id", d) } -// GetLimit is a shotcut to get the limit from the request URL parameters +// GetLimit is a shortcut to get the limit from the request URL parameters func GetLimit(r *http.Request, d string) string { return GetParam(r, "limit", d) } -// GetQuery is a shotcut to get the sort from the request URL parameters +// GetQuery is a shortcut to get the sort from the request URL parameters func GetQuery(r *http.Request, d string) string { return GetParam(r, "query", d) } diff --git a/backend/pkgs/server/response_error_builder.go b/backend/pkgs/server/response_error_builder.go deleted file mode 100644 index cc573e2..0000000 --- a/backend/pkgs/server/response_error_builder.go +++ /dev/null @@ -1,76 +0,0 @@ -package server - -import ( - "net/http" -) - -type ValidationError struct { - Field string `json:"field"` - Reason string `json:"reason"` -} - -type ValidationErrors []ValidationError - -func (ve *ValidationErrors) HasErrors() bool { - if (ve == nil) || (len(*ve) == 0) { - return false - } - - for _, err := range *ve { - if err.Field != "" { - return true - } - } - return false -} - -func (ve ValidationErrors) Append(field, reasons string) ValidationErrors { - return append(ve, ValidationError{ - Field: field, - Reason: reasons, - }) -} - -// ErrorBuilder is a helper type to build a response that contains an array of errors. -// Typical use cases are for returning an array of validation errors back to the user. -// -// Example: -// -// { -// "errors": [ -// "invalid id", -// "invalid name", -// "invalid description" -// ], -// "message": "Unprocessable Entity", -// "status": 422 -// } -type ErrorBuilder struct { - errs []string -} - -// HasErrors returns true if the ErrorBuilder has any errors. -func (eb *ErrorBuilder) HasErrors() bool { - if (eb.errs == nil) || (len(eb.errs) == 0) { - return false - } - return true -} - -// AddError adds an error to the ErrorBuilder if an error is not nil. If the -// Error is nil, then nothing is added. -func (eb *ErrorBuilder) AddError(err error) { - if err != nil { - if eb.errs == nil { - eb.errs = make([]string, 0) - } - - eb.errs = append(eb.errs, err.Error()) - } -} - -// Respond sends a JSON response with the ErrorBuilder's errors. If there are no errors, then -// the errors field will be an empty array. -func (eb *ErrorBuilder) Respond(w http.ResponseWriter, statusCode int) { - _ = Respond(w, statusCode, Wrap(nil).AddError(http.StatusText(statusCode), eb.errs)) -} diff --git a/backend/pkgs/server/response_error_builder_test.go b/backend/pkgs/server/response_error_builder_test.go deleted file mode 100644 index 689faaa..0000000 --- a/backend/pkgs/server/response_error_builder_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package server - -import ( - "encoding/json" - "errors" - "net/http" - "net/http/httptest" - "testing" - - "github.com/hay-kot/homebox/backend/pkgs/faker" - "github.com/stretchr/testify/assert" -) - -func Test_ErrorBuilder_HasErrors_NilList(t *testing.T) { - t.Parallel() - - var ebNilList = ErrorBuilder{} - assert.False(t, ebNilList.HasErrors(), "ErrorBuilder.HasErrors() should return false when list is nil") - -} - -func Test_ErrorBuilder_HasErrors_EmptyList(t *testing.T) { - t.Parallel() - - var ebEmptyList = ErrorBuilder{ - errs: []string{}, - } - assert.False(t, ebEmptyList.HasErrors(), "ErrorBuilder.HasErrors() should return false when list is empty") - -} - -func Test_ErrorBuilder_HasErrors_WithError(t *testing.T) { - t.Parallel() - - var ebList = ErrorBuilder{} - ebList.AddError(errors.New("test error")) - - assert.True(t, ebList.HasErrors(), "ErrorBuilder.HasErrors() should return true when list is not empty") - -} - -func Test_ErrorBuilder_AddError(t *testing.T) { - t.Parallel() - - randomError := make([]error, 10) - - f := faker.NewFaker() - - errorStrings := make([]string, 10) - - for i := 0; i < 10; i++ { - err := errors.New(f.Str(10)) - randomError[i] = err - errorStrings[i] = err.Error() - } - - // Check Results - var ebList = ErrorBuilder{} - - for _, err := range randomError { - ebList.AddError(err) - } - - assert.Equal(t, errorStrings, ebList.errs, "ErrorBuilder.AddError() should add an error to the list") -} - -func Test_ErrorBuilder_Respond(t *testing.T) { - t.Parallel() - - f := faker.NewFaker() - - randomError := make([]error, 5) - - for i := 0; i < 5; i++ { - err := errors.New(f.Str(5)) - randomError[i] = err - } - - // Check Results - var ebList = ErrorBuilder{} - - for _, err := range randomError { - ebList.AddError(err) - } - - fakeWriter := httptest.NewRecorder() - - ebList.Respond(fakeWriter, 422) - - assert.Equal(t, 422, fakeWriter.Code, "ErrorBuilder.Respond() should return a status code of 422") - - // Check errors payload is correct - - errorsStruct := struct { - Errors []string `json:"details"` - Message string `json:"message"` - Error bool `json:"error"` - }{ - Errors: ebList.errs, - Message: http.StatusText(http.StatusUnprocessableEntity), - Error: true, - } - - asJson, _ := json.Marshal(errorsStruct) - assert.JSONEq(t, string(asJson), fakeWriter.Body.String(), "ErrorBuilder.Respond() should return a JSON response with the errors") - -} diff --git a/backend/pkgs/server/result.go b/backend/pkgs/server/result.go index 656d17b..69dcf81 100644 --- a/backend/pkgs/server/result.go +++ b/backend/pkgs/server/result.go @@ -17,15 +17,3 @@ func Wrap(data interface{}) Result { Item: data, } } - -func (r Result) AddMessage(message string) Result { - r.Message = message - return r -} - -func (r Result) AddError(err string, details interface{}) Result { - r.Message = err - r.Details = details - r.Error = true - return r -}