{"action":"created","issue":{"url":"https://api.github.com/repos/vert-x3/vertx-web/issues/201","labels_url":"https://api.github.com/repos/vert-x3/vertx-web/issues/201/labels{/name}","comments_url":"https://api.github.com/repos/vert-x3/vertx-web/issues/201/comments","events_url":"https://api.github.com/repos/vert-x3/vertx-web/issues/201/events","html_url":"https://github.com/vert-x3/vertx-web/issues/201","id":108506533,"number":201,"title":"Can't handle NOT FOUND (404) by using custom failureHandler for REST API","user":{"login":"EmadAlblueshi","id":6061055,"avatar_url":"https://avatars.githubusercontent.com/u/6061055?v=3","gravatar_id":"","url":"https://api.github.com/users/EmadAlblueshi","html_url":"https://github.com/EmadAlblueshi","followers_url":"https://api.github.com/users/EmadAlblueshi/followers","following_url":"https://api.github.com/users/EmadAlblueshi/following{/other_user}","gists_url":"https://api.github.com/users/EmadAlblueshi/gists{/gist_id}","starred_url":"https://api.github.com/users/EmadAlblueshi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EmadAlblueshi/subscriptions","organizations_url":"https://api.github.com/users/EmadAlblueshi/orgs","repos_url":"https://api.github.com/users/EmadAlblueshi/repos","events_url":"https://api.github.com/users/EmadAlblueshi/events{/privacy}","received_events_url":"https://api.github.com/users/EmadAlblueshi/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/vert-x3/vertx-web/labels/invalid","name":"invalid","color":"e6e6e6"},{"url":"https://api.github.com/repos/vert-x3/vertx-web/labels/question","name":"question","color":"cc317c"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-09-27T01:15:55Z","updated_at":"2015-09-27T20:11:19Z","closed_at":null,"body":"I'm trying to handle the not found (404) by using custom failureHandler to get the response as a JSON format to the client  \r\n\r\n~~~java\r\n\r\nimport io.netty.handler.codec.http.HttpResponseStatus;\r\nimport io.vertx.core.AbstractVerticle;\r\nimport io.vertx.core.Future;\r\nimport io.vertx.core.http.HttpHeaders;\r\nimport io.vertx.core.http.HttpServer;\r\nimport io.vertx.core.json.JsonObject;\r\nimport io.vertx.ext.web.Router;\r\n\r\n\r\npublic class RestApiVerticle extends AbstractVerticle {\r\n\r\n\t@Override\r\n\tpublic void start(Future<Void> startFuture) throws Exception {\r\n\t\t\r\n\t\tRouter router = Router.router(vertx);\r\n\t\t\r\n\t\trouter.route().handler(ctx -> {\r\n\t\t\tctx.response()\r\n        \t\t.putHeader(\"Cache-Control\", \"no-store, no-cache\");\r\n\t\t\tctx.next();\t\t\t\t\r\n\t\t});\r\n\t\t\r\n\t    router.route(\"/api*\")\r\n\t    \t.produces(\"application/json\")\r\n\t    \t.consumes(\"application/json\")\r\n\t    \t.failureHandler(ctx -> {\r\n\t    \t\t\t\t\r\n\t\t\t\tfinal JsonObject json = new JsonObject()\r\n\t\t\t\t.put(\"timestamp\", System.nanoTime())\r\n\t\t\t\t.put(\"status\", ctx.statusCode())\r\n\t\t\t\t.put(\"error\", HttpResponseStatus.valueOf(ctx.statusCode()).reasonPhrase())\r\n\t\t\t\t.put(\"path\", ctx.request().path());\r\n\t\t\t\t\r\n\t\t\t\tfinal String message = ctx.get(\"message\");\r\n\t\t\t\t\r\n\t\t\t\tif(message != null) {\r\n\t\t\t\t\tjson.put(\"message\", message);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t    \tctx.response().putHeader(HttpHeaders.CONTENT_TYPE,\"application/json; charset=utf-8\");\r\n\t\t    \tctx.response().end(json.encodePrettily());\t    \t\r\n\t    \t\r\n\t    \t});\r\n\t    \r\n\t    router.get(\"/api/greeting\")\r\n    \t\t.produces(\"application/json\")\r\n    \t\t.consumes(\"application/json\")\r\n    \t\t.handler(ctx -> {\r\n    \t\t\t\t\r\n\t\t\t\tfinal JsonObject greeting = new JsonObject()\r\n\t\t\t\t\t.put(\"greeting\", \"Hello!\");\r\n\t\t\t\t\r\n\t\t    \tctx.response().putHeader(HttpHeaders.CONTENT_TYPE,\"application/json; charset=utf-8\");\r\n\t\t    \tctx.response().end(greeting.encodePrettily());\r\n    \t\r\n    \t\t});\r\n\t    \r\n\t    HttpServer httpServer = vertx.createHttpServer();\r\n\t    httpServer\r\n\t    \t.requestHandler(router::accept)\r\n\t    \t.listen(9090, \"localhost\", listenHandler -> {\r\n\t\t    \tif (listenHandler.succeeded()) {\r\n\t\t\t\t\tstartFuture.complete();\r\n\t\t\t\t}\r\n\t\t    \tif(listenHandler.failed()) {\r\n\t\t    \t\tstartFuture.fail(listenHandler.cause());\r\n\t\t    \t}\r\n\t    \t});\r\n\t}\r\n}\r\n~~~\r\nIf I run below command which is the ideal scenario \r\n~~~code\r\n\r\ncurl -X GET -H \"Content-type: application/json\" http://localhost:9090/api/greeting\r\n\r\n~~~\r\n\r\nI will get below result \r\n\r\n~~~javascript\r\n{\r\n    \"greeting\": \"Hello!\"\r\n}\r\n~~~\r\n\r\nBut If I run below command which is not found resource\r\n~~~code\r\n\r\ncurl -X GET -H \"Content-type: application/json\" http://localhost:9090/api/blah\r\n\r\n~~~\r\n\r\nI will get below result \r\n\r\n~~~html\r\n<html>\r\n    <body>\r\n        <h1>Resource not found</h1>\r\n    </body>\r\n</html>\r\n~~~\r\n"},"comment":{"url":"https://api.github.com/repos/vert-x3/vertx-web/issues/comments/143591498","html_url":"https://github.com/vert-x3/vertx-web/issues/201#issuecomment-143591498","issue_url":"https://api.github.com/repos/vert-x3/vertx-web/issues/201","id":143591498,"user":{"login":"EmadAlblueshi","id":6061055,"avatar_url":"https://avatars.githubusercontent.com/u/6061055?v=3","gravatar_id":"","url":"https://api.github.com/users/EmadAlblueshi","html_url":"https://github.com/EmadAlblueshi","followers_url":"https://api.github.com/users/EmadAlblueshi/followers","following_url":"https://api.github.com/users/EmadAlblueshi/following{/other_user}","gists_url":"https://api.github.com/users/EmadAlblueshi/gists{/gist_id}","starred_url":"https://api.github.com/users/EmadAlblueshi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EmadAlblueshi/subscriptions","organizations_url":"https://api.github.com/users/EmadAlblueshi/orgs","repos_url":"https://api.github.com/users/EmadAlblueshi/repos","events_url":"https://api.github.com/users/EmadAlblueshi/events{/privacy}","received_events_url":"https://api.github.com/users/EmadAlblueshi/received_events","type":"User","site_admin":false},"created_at":"2015-09-27T20:11:19Z","updated_at":"2015-09-27T20:11:19Z","body":"@pmlopes I think the last handler is much better to me as shown below :\r\n\r\n\r\n~~~java\r\nrouter.route().failureHandler(ctx -> {\r\n\t\r\n    final JsonObject error = new JsonObject()\r\n    .put(\"timestamp\", System.nanoTime())\r\n    .put(\"exception\", ctx.failure().getClass().getName())\r\n    .put(\"exceptionMessage\", ctx.failure().getMessage())\r\n    .put(\"path\", ctx.request().path());\r\n    \r\n    ctx.response().putHeader(HttpHeaders.CONTENT_TYPE,\"application/json; charset=utf-8\");\r\n    ctx.response().end(error.encode());\r\n\t\r\n});\r\n\r\nrouter.get(\"/api/greeting\")\r\n.produces(\"application/json\")\r\n.consumes(\"application/json\")\r\n.handler(ctx -> {\r\n\r\n    final JsonObject greeting = new JsonObject()\r\n        .put(\"greeting\", \"Hello!\");\r\n\r\n    ctx.response().putHeader(HttpHeaders.CONTENT_TYPE,\"application/json; charset=utf-8\");\r\n    ctx.response().end(greeting.encode());\r\n\r\n});\r\n\r\nrouter.route().handler(ctx -> {\r\n\tctx.fail(new RuntimeException(\"Not found\"));\r\n});\r\n~~~\r\n\r\nBut I suggest if it possible to add and extra parameter to the fail method for the RoutingContext with something like \r\n\r\n~~~java\r\n// Exception with status code \r\nrouter.route().handler(ctx -> {\r\n\tctx.fail(new RuntimeException(\"Not found\") , 404);\r\n});\r\n~~~\r\n\r\nThank you :+1: "}}