diff --git a/internal/test/chi/oapi_validate_test.go b/internal/test/chi/oapi_validate_test.go index 162da25..9e8baa6 100644 --- a/internal/test/chi/oapi_validate_test.go +++ b/internal/test/chi/oapi_validate_test.go @@ -391,6 +391,19 @@ func testRequestValidatorBasicFunctions(t *testing.T, r *chi.Mux) { called = false } + // Send a request with wrong HTTP method + { + body := struct { + Name string `json:"name"` + }{ + Name: "Marcin", + } + rec := doPost(t, r, "http://deepmap.ai/resource", body) + assert.Equal(t, http.StatusMethodNotAllowed, rec.Code) + assert.False(t, called, "Handler should not have been called") + called = false + } + // Add a handler for the POST message r.Post("/resource", func(w http.ResponseWriter, r *http.Request) { called = true diff --git a/internal/test/gorilla/oapi_validate_test.go b/internal/test/gorilla/oapi_validate_test.go index 87f90d6..129c2d2 100644 --- a/internal/test/gorilla/oapi_validate_test.go +++ b/internal/test/gorilla/oapi_validate_test.go @@ -391,6 +391,19 @@ func testRequestValidatorBasicFunctions(t *testing.T, r *mux.Router) { called = false } + // Send a request with wrong HTTP method + { + body := struct { + Name string `json:"name"` + }{ + Name: "Marcin", + } + rec := doPost(t, r, "http://deepmap.ai/resource", body) + assert.Equal(t, http.StatusMethodNotAllowed, rec.Code) + assert.False(t, called, "Handler should not have been called") + called = false + } + // Add a handler for the POST message r.HandleFunc("/resource", func(w http.ResponseWriter, r *http.Request) { called = true diff --git a/internal/test/nethttp/oapi_validate_test.go b/internal/test/nethttp/oapi_validate_test.go index 8fc6df0..591d88f 100644 --- a/internal/test/nethttp/oapi_validate_test.go +++ b/internal/test/nethttp/oapi_validate_test.go @@ -62,6 +62,27 @@ func doPost(t *testing.T, mux http.Handler, rawURL string, jsonBody interface{}) return rr } +func doPatch(t *testing.T, mux http.Handler, rawURL string, jsonBody interface{}) *httptest.ResponseRecorder { + u, err := url.Parse(rawURL) + if err != nil { + t.Fatalf("Invalid url: %s", rawURL) + } + + data, err := json.Marshal(jsonBody) + require.NoError(t, err) + + req, err := http.NewRequest(http.MethodPatch, u.String(), bytes.NewReader(data)) + require.NoError(t, err) + + req.Header.Set("content-type", "application/json") + + rr := httptest.NewRecorder() + + mux.ServeHTTP(rr, req) + + return rr +} + // use wraps a given http.ServeMux with middleware for execution func use(r *http.ServeMux, mw func(next http.Handler) http.Handler) http.Handler { return mw(r) @@ -434,6 +455,19 @@ func testRequestValidatorBasicFunctions(t *testing.T, r *http.ServeMux, mw func( called = false } + // Send a request with wrong method + { + body := struct { + Name string `json:"name"` + }{ + Name: "Marcin", + } + rec := doPatch(t, server, "http://deepmap.ai/resource", body) + assert.Equal(t, http.StatusMethodNotAllowed, rec.Code) + assert.False(t, called, "Handler should not have been called") + called = false + } + called = false // Send a good request body { diff --git a/oapi_validate.go b/oapi_validate.go index 9e8b126..eef83c2 100644 --- a/oapi_validate.go +++ b/oapi_validate.go @@ -87,6 +87,10 @@ func validateRequest(r *http.Request, router routers.Router, options *Options) ( // Find route route, pathParams, err := router.FindRoute(r) if err != nil { + if errors.Is(err, routers.ErrMethodNotAllowed) { + return http.StatusMethodNotAllowed, err + } + return http.StatusNotFound, err // We failed to find a matching route for the request. } diff --git a/oapi_validate_example_test.go b/oapi_validate_example_test.go index d0cab9a..3e2944f 100644 --- a/oapi_validate_example_test.go +++ b/oapi_validate_example_test.go @@ -163,6 +163,27 @@ components: logResponseBody(rr) fmt.Println() + // ================================================================================ + fmt.Println("# A request with an invalid HTTP method, to a valid path, is rejected with an HTTP 405 Method Not Allowed") + body = map[string]string{ + "invalid": "not expected", + } + + data, err = json.Marshal(body) + must(err) + + req, err = http.NewRequest(http.MethodPatch, "/resource", bytes.NewReader(data)) + must(err) + req.Header.Set("Content-Type", "application/json") + + rr = httptest.NewRecorder() + + server.ServeHTTP(rr, req) + + fmt.Printf("Received an HTTP %d response. Expected HTTP 405\n", rr.Code) + logResponseBody(rr) + fmt.Println() + // ================================================================================ fmt.Println("# A request that is well-formed is passed through to the Handler") body = map[string]string{ @@ -207,6 +228,10 @@ components: // Received an HTTP 400 response. Expected HTTP 400 // Response body: request body has an error: doesn't match schema: property "invalid" is unsupported // + // # A request with an invalid HTTP method, to a valid path, is rejected with an HTTP 405 Method Not Allowed + // Received an HTTP 405 response. Expected HTTP 405 + // Response body: method not allowed + // // # A request that is well-formed is passed through to the Handler // POST /resource was called // Received an HTTP 204 response. Expected HTTP 204