diff --git a/vertx-web-openapi-router/src/main/java/io/vertx/ext/web/openapi/router/impl/RouterBuilderImpl.java b/vertx-web-openapi-router/src/main/java/io/vertx/ext/web/openapi/router/impl/RouterBuilderImpl.java index 6ad05f20f8..1afd0e3ddb 100644 --- a/vertx-web-openapi-router/src/main/java/io/vertx/ext/web/openapi/router/impl/RouterBuilderImpl.java +++ b/vertx-web-openapi-router/src/main/java/io/vertx/ext/web/openapi/router/impl/RouterBuilderImpl.java @@ -147,9 +147,9 @@ public Router createRouter() { openAPIRoute.getFailureHandlers().forEach(route::failureHandler); } else { LOG.warn("No handlers found for operation " + operation.getOperationId() + " - skipping route creation"); - // terminate the request with 503 (Not Implemented) + // terminate the request with 501 (Not Implemented) route - .handler(ctx -> ctx.response().setStatusCode(503).end()); + .handler(ctx -> ctx.response().setStatusCode(501).end()); } } } diff --git a/vertx-web-openapi-router/src/test/java/io/vertx/router/test/e2e/RouterBuilderTest.java b/vertx-web-openapi-router/src/test/java/io/vertx/router/test/e2e/RouterBuilderTest.java index 8e09c8ea64..dcdfde1a18 100644 --- a/vertx-web-openapi-router/src/test/java/io/vertx/router/test/e2e/RouterBuilderTest.java +++ b/vertx-web-openapi-router/src/test/java/io/vertx/router/test/e2e/RouterBuilderTest.java @@ -35,6 +35,8 @@ import static com.google.common.truth.Truth.assertThat; import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; +import static io.netty.handler.codec.http.HttpResponseStatus.NOT_IMPLEMENTED; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.vertx.core.http.HttpMethod.GET; import static io.vertx.core.http.HttpMethod.POST; import static io.vertx.ext.web.openapi.router.RequestExtractor.withBodyHandler; @@ -157,4 +159,84 @@ void testRouterWithInvalidRequest(VertxTestContext testContext) { }) .onFailure(testContext::failNow); } + + @Test + @Timeout(value = 2, timeUnit = TimeUnit.SECONDS) + void testRouterWithNoHandlerReturns501NotImplemented(VertxTestContext testContext) { + Path pathDereferencedContract = ResourceHelper.TEST_RESOURCE_PATH.resolve("v3.1").resolve("petstore.json"); + createServer(pathDereferencedContract, rb -> { + // Intentionally do NOT add any handlers for the operations + // This will trigger the default behavior of returning 501 Not Implemented + return Future.succeededFuture(rb); + }).compose(v -> createRequest(GET, "/v1/pets").send()) + .onSuccess(response -> testContext.verify(() -> { + assertThat(response.statusCode()).isEqualTo(NOT_IMPLEMENTED.code()); + testContext.completeNow(); + })) + .onFailure(testContext::failNow); + } + + @Test + @Timeout(value = 2, timeUnit = TimeUnit.SECONDS) + void testRouterWithNoHandlersReturns501ForAllOperations(VertxTestContext testContext) { + Checkpoint cpAllOperations = testContext.checkpoint(3); + + Path pathDereferencedContract = ResourceHelper.TEST_RESOURCE_PATH.resolve("v3.1").resolve("petstore.json"); + createServer(pathDereferencedContract, rb -> Future.succeededFuture(rb)) + .compose(v -> createRequest(GET, "/v1/pets").send()) + .onSuccess(response -> testContext.verify(() -> { + assertThat(response.statusCode()).isEqualTo(NOT_IMPLEMENTED.code()); + cpAllOperations.flag(); + })) + .compose(v -> { + JsonObject bodyJson = new JsonObject().put("id", 1).put("name", "FooBar"); + return createRequest(POST, "/v1/pets").sendJsonObject(bodyJson); + }) + .onSuccess(response -> testContext.verify(() -> { + assertThat(response.statusCode()).isEqualTo(NOT_IMPLEMENTED.code()); + cpAllOperations.flag(); + })) + .compose(v -> createRequest(GET, "/v1/pets/123").send()) + .onSuccess(response -> testContext.verify(() -> { + assertThat(response.statusCode()).isEqualTo(NOT_IMPLEMENTED.code()); + cpAllOperations.flag(); + })) + .onFailure(testContext::failNow); + } + + @Test + @Timeout(value = 2, timeUnit = TimeUnit.SECONDS) + void testRouterWithPartialHandlersReturns501ForUnimplemented(VertxTestContext testContext) { + Checkpoint cpAllOperations = testContext.checkpoint(3); + + Path pathDereferencedContract = ResourceHelper.TEST_RESOURCE_PATH.resolve("v3.1").resolve("petstore.json"); + createServer(pathDereferencedContract, rb -> { + // Add handlers for only listPets and createPets operations but intentionally do NOT add handler for showPetById + rb.getRoute("listPets") + .setDoSecurity(false) + .addHandler(rc -> rc.response().setStatusCode(OK.code()).end("[]")); + rb.getRoute("createPets") + .setDoSecurity(false) + .addHandler(rc -> rc.response().setStatusCode(OK.code()).end()); + return Future.succeededFuture(rb); + }).compose(v -> createRequest(GET, "/v1/pets").send()) + .onSuccess(response -> testContext.verify(() -> { + assertThat(response.statusCode()).isEqualTo(OK.code()); + cpAllOperations.flag(); + })) + .compose(v -> { + JsonObject bodyJson = new JsonObject().put("id", 1).put("name", "FooBar"); + return createRequest(POST, "/v1/pets").sendJsonObject(bodyJson); + }) + .onSuccess(response -> testContext.verify(() -> { + assertThat(response.statusCode()).isEqualTo(OK.code()); + cpAllOperations.flag(); + })) + .compose(v -> createRequest(GET, "/v1/pets/123").send()) + .onSuccess(response -> testContext.verify(() -> { + assertThat(response.statusCode()).isEqualTo(NOT_IMPLEMENTED.code()); + cpAllOperations.flag(); + })) + .onFailure(testContext::failNow); + } }