package app import ( "errors" "net/http" "git.threesix.ai/jordan/feat-dev-e2e3/pkg/httperror" "git.threesix.ai/jordan/feat-dev-e2e3/pkg/httpresponse" "git.threesix.ai/jordan/feat-dev-e2e3/pkg/httpvalidation" ) // Bind decodes JSON from the request body into v. // Returns an HTTPError on failure that can be returned directly from a HandlerFunc. // // Usage: // // func CreateUser(w http.ResponseWriter, r *http.Request) error { // var req CreateUserRequest // if err := app.Bind(r, &req); err != nil { // return err // Returns typed HTTPError // } // // req is now decoded // } func Bind(r *http.Request, v any) error { if err := httpresponse.DecodeJSON(r, v); err != nil { if errors.Is(err, httpresponse.ErrEmptyBody) { return httperror.BadRequest("request body is required") } return httperror.BadRequest("invalid request body") } return nil } // BindStrict decodes JSON from the request body with strict field checking. // Unknown fields in the JSON will cause an error. func BindStrict(r *http.Request, v any) error { if err := httpresponse.DecodeJSONStrict(r, v); err != nil { if errors.Is(err, httpresponse.ErrEmptyBody) { return httperror.BadRequest("request body is required") } if errors.Is(err, httpresponse.ErrUnknownFields) { return httperror.BadRequest("unknown fields in request body") } return httperror.BadRequest("invalid request body") } return nil } // BindAndValidate decodes JSON and validates using httpvalidation. // Returns a validation error with field-level details if validation fails. // // Usage: // // type CreateUserRequest struct { // Name string `json:"name" validate:"required,min=1,max=100"` // Email string `json:"email" validate:"required,email"` // } // // func CreateUser(w http.ResponseWriter, r *http.Request) error { // var req CreateUserRequest // if err := app.BindAndValidate(r, &req); err != nil { // return err // } // // req is decoded and validated // } func BindAndValidate(r *http.Request, v any) error { // Decode JSON if err := Bind(r, v); err != nil { return err } // Validate struct if details := httpvalidation.ValidateStruct(v); len(details) > 0 { return httperror.WithDetails(httperror.Validation("validation failed"), details) } return nil } // BindAndValidateStrict decodes JSON with strict field checking and validates. func BindAndValidateStrict(r *http.Request, v any) error { // Decode JSON strictly if err := BindStrict(r, v); err != nil { return err } // Validate struct if details := httpvalidation.ValidateStruct(v); len(details) > 0 { return httperror.WithDetails(httperror.Validation("validation failed"), details) } return nil }