Skip to content

Commit

Permalink
#216 - Add message to request (extra) and handle in status handler
Browse files Browse the repository at this point in the history
  • Loading branch information
BowlOfSoup committed Jul 11, 2024
1 parent 8c398da commit 4ab940e
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 1 deletion.
1 change: 1 addition & 0 deletions lang/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var enUS = &Language{
"auth.jwt-invalid": "Your authentication token is invalid.",
"auth.jwt-not-valid-yet": "Your authentication token is not valid yet.",
"auth.jwt-expired": "Your authentication token is expired.",
"request.json-empty-body": "The request Content-Type indicates JSON, but the request body is empty",
},
validation: validationLines{
rules: map[string]string{
Expand Down
4 changes: 4 additions & 0 deletions middleware/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package parse
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
Expand Down Expand Up @@ -73,6 +74,9 @@ func (m *Middleware) Handle(next goyave.Handler) goyave.Handler {
var body any
if err := json.Unmarshal(bodyBytes, &body); err != nil {
response.Status(http.StatusBadRequest)
r.Extra[goyave.ExtraRequestError{}] = []error{
fmt.Errorf("request.json-empty-body"),
}
}
r.Data = body
} else {
Expand Down
3 changes: 3 additions & 0 deletions middleware/parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package parse

import (
"bytes"
"fmt"
"mime/multipart"
"net/http"
"strings"
Expand Down Expand Up @@ -107,6 +108,8 @@ func TestParseMiddleware(t *testing.T) {
})
assert.NoError(t, result.Body.Close())
assert.Equal(t, http.StatusBadRequest, result.StatusCode)
assert.NotNil(t, request.Extra[goyave.ExtraRequestError{}])
assert.Contains(t, request.Extra[goyave.ExtraRequestError{}].([]error), fmt.Errorf("request.json-empty-body"))
})

t.Run("Multipart", func(t *testing.T) {
Expand Down
6 changes: 5 additions & 1 deletion request.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@ type (
// ExtraQueryValidationError the key used in `Context.Extra` to
// store the query validation errors.
ExtraQueryValidationError struct{}

// ExtraRequestError the key used in `Context.Extra` to
// store specific request errors.
ExtraRequestError struct{}
)

// Request represents an http request received by the server.
// Request represents a http request received by the server.
type Request struct {
httpRequest *http.Request
Now time.Time
Expand Down
1 change: 1 addition & 0 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ func NewRouter(server *Server) *Router {
for i := 400; i <= 418; i++ {
router.StatusHandler(&ErrorStatusHandler{}, i)
}
router.StatusHandler(&RequestErrorStatusHandler{}, http.StatusBadRequest)
router.StatusHandler(&ValidationStatusHandler{}, http.StatusUnprocessableEntity)
for i := 423; i <= 426; i++ {
router.StatusHandler(&ErrorStatusHandler{}, i)
Expand Down
34 changes: 34 additions & 0 deletions status_handler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package goyave

import (
"fmt"
"net/http"

"goyave.dev/goyave/v5/validation"
Expand Down Expand Up @@ -48,6 +49,39 @@ func (*ErrorStatusHandler) Handle(response *Response, _ *Request) {
response.JSON(response.GetStatus(), message)
}

type RequestErrorStatusHandler struct {

Check failure on line 52 in status_handler.go

View workflow job for this annotation

GitHub Actions / Lint

exported: exported type RequestErrorStatusHandler should have comment or be unexported (revive)
Component
}

func (h *RequestErrorStatusHandler) Handle(response *Response, request *Request) {

Check failure on line 56 in status_handler.go

View workflow job for this annotation

GitHub Actions / Lint

exported: exported method RequestErrorStatusHandler.Handle should have comment or be unexported (revive)
var errorMessages []string
var lang string

if request.Lang == nil {
lang = h.Lang().GetDefault().Name()
} else {
lang = request.Lang.Name()
}

if e, ok := request.Extra[ExtraRequestError{}]; ok {
switch v := e.(type) {
case []error:
for _, err := range v {
errorMessages = append(errorMessages, h.Lang().GetLanguage(lang).Get(err.Error()))
}
case string:
errorMessages = append(errorMessages, h.Lang().GetLanguage(lang).Get(v))
default:
errorMessages = append(errorMessages, h.Lang().GetLanguage(lang).Get(fmt.Sprintf("%v", v)))
}
}

messages := map[string][]string{
"error": errorMessages,
}
response.JSON(response.GetStatus(), messages)
}

// ValidationStatusHandler for HTTP 422 errors.
// Writes the validation errors to the response.
type ValidationStatusHandler struct {
Expand Down
19 changes: 19 additions & 0 deletions status_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package goyave

import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -131,3 +132,21 @@ func TestValidationStatusHandler(t *testing.T) {

assert.Equal(t, "{\"error\":{\"body\":{\"fields\":{\"field\":{\"errors\":[\"The field is required\"]}},\"errors\":[\"The body is required\"]},\"query\":{\"fields\":{\"query\":{\"errors\":[\"The query is required\"]}}}}}\n", string(body))
}

func TestRequestErrorStatusHandler(t *testing.T) {
req, resp, recorder := prepareStatusHandlerTest()
handler := &RequestErrorStatusHandler{}
handler.Init(resp.server)

req.Extra[ExtraRequestError{}] = []error{fmt.Errorf("request.json-empty-body")}

handler.Handle(resp, req)

res := recorder.Result()
body, err := io.ReadAll(res.Body)

assert.NoError(t, res.Body.Close())
require.NoError(t, err)

assert.Equal(t, "{\"error\":[\"The request Content-Type indicates JSON, but the request body is empty\"]}\n", string(body))
}

0 comments on commit 4ab940e

Please sign in to comment.