diff --git a/api.go b/api.go index 5b3d9e4e..30ecc9c5 100644 --- a/api.go +++ b/api.go @@ -3,6 +3,7 @@ package huma import ( "context" "encoding/json" + "errors" "fmt" "io" "mime/multipart" @@ -19,6 +20,8 @@ import ( var rxSchema = regexp.MustCompile(`#/components/schemas/([^"]+)`) +var ErrUnknownContentType = errors.New("unknown content type") + // Resolver runs a `Resolve` function after a request has been parsed, enabling // you to run custom validation or other code that can modify the request and / // or return errors. @@ -229,7 +232,7 @@ func (a *api) Unmarshal(contentType string, data []byte, v any) error { } f, ok := a.formats[ct] if !ok { - return fmt.Errorf("unknown content type: %s", contentType) + return fmt.Errorf("%w: %s", ErrUnknownContentType, contentType) } return f.Unmarshal(data, v) } diff --git a/huma.go b/huma.go index 547f654a..4f89e422 100644 --- a/huma.go +++ b/huma.go @@ -10,6 +10,7 @@ package huma import ( "bytes" "context" + "errors" "fmt" "io" "net" @@ -824,8 +825,10 @@ func Register[I, O any](api API, op Operation, handler func(context.Context, *I) // expected struct type to call the handler. var parsed any if err := api.Unmarshal(ctx.Header("Content-Type"), body, &parsed); err != nil { - // TODO: handle not acceptable errStatus = http.StatusBadRequest + if errors.Is(err, ErrUnknownContentType) { + errStatus = http.StatusUnsupportedMediaType + } res.Errors = append(res.Errors, &ErrorDetail{ Location: "body", Message: err.Error(), diff --git a/huma_test.go b/huma_test.go index 7b02df56..21af0418 100644 --- a/huma_test.go +++ b/huma_test.go @@ -292,6 +292,31 @@ func TestFeatures(t *testing.T) { assert.Equal(t, http.StatusBadRequest, resp.Code) }, }, + { + Name: "request-body-unsupported-media-type", + Register: func(t *testing.T, api huma.API) { + huma.Register(api, huma.Operation{ + Method: http.MethodPut, + Path: "/body", + }, func(ctx context.Context, input *struct { + RawBody []byte + Body struct { + Name string `json:"name"` + } + }) (*struct{}, error) { + assert.Equal(t, `{"name":"foo"}`, string(input.RawBody)) + assert.Equal(t, "foo", input.Body.Name) + return nil, nil + }) + }, + Method: http.MethodPut, + URL: "/body", + Headers: map[string]string{"Content-Type": "application/foo"}, + Body: `abcd`, + Assert: func(t *testing.T, resp *httptest.ResponseRecorder) { + assert.Equal(t, http.StatusUnsupportedMediaType, resp.Code) + }, + }, { Name: "request-body-file-upload", Register: func(t *testing.T, api huma.API) {