javavert.xapi-designvert.x-webclient

Forwarding requests to different verticle based on path param (Vert.x)


I'm using Vert.x for the first time ever to try to build an API in Java. Right now I can use an eventBus in my main verticle to forward certain routes like /example/:name etc to a handler that sends an eventBus message to it's respective verticle.

  void helloPOC(RoutingContext context) {
    vertx
        .eventBus()
        .request(
            "poc.hello",
            "",
            reply -> {
              context.response().end((String) reply.result().body());
            });
  }

However, it doesn't make sense to have so many handlers in my main verticle. I don't assume this endpoint is going to be very fancy and have a lot of variables involved, but I want to be able to have a handler that can take all requests like /example/* to be handled in it's respective exampleVerticle.

I could find any resources to do so but essentially this is how some pseudocode for what I want to be able to do.

// mainVerticle.java

start(){
  router.get("/example/*").handler(this::exampleHandler);
}

exampleHandler(){
  // routes to exampleVerticle
}
//exampleVerticle.java
start(){
  router.get("/example/hello").handler(this::helloExample);
}

void helloExample(RoutingContext context) {
  vertx
      .eventBus()
      .request(
          "example.hello",
          "",
          reply -> {
            // some sort of reply
          });
}

Obviously I don't have much of an idea what I'm doing but I hope what I'm trying to do makes sense.

Thanks in advance!


Solution

  • Vert.x, as a toolkit and not a framework, does not prescribe how to organize your source code. You can do it as you like and it should work.

    For example, you could put all your handlers in a utility class and wire them from another place:

    public final class Handlers {
        private Handlers() {}
    
        public Handler<RoutingContext> getOranges() {
            return ctx -> ctx.end("Juicy Oranges");
        }
    
        public Handler<RoutingContext> getBananas() {
            return ctx -> ctx.end("Tasty Bananas");
        }
    }
    

    And in another Verticle:

    router
        .get("/oranges").handler(Handlers.getOranges())
        .get("/bananas").handler(Handlers.getBananas());
    

    Frankly, most of the time, I just deploy one HttpVerticle from my MainVerticle like so:

    public final class HttpVerticle extends AbstractVerticle {
        
        public void start(Promise<Void> startPromise) {
            var router = Router.router(vertx);
            router
                .get("/bananas").handler(this::handleBananas)
                .get("/oranges").handler(this::handleOranges);
            vertx.createHttpServer()
                .requestHandler(router)
                .listen(8080)
                .onSuccess(__ -> startPromise.complete(null))
                .onFailure(ex -> startPromise.fail(ex));
        }
    
    }
    

    And in MainVerticle:

    public final class MainVerticle extends AbstractVerticle {
    
        public void start(Promise<Void> startPromise) {
            vertx.deployVerticle(new HttpVerticle())
                .onSuccess(__ -> startPromise.complete(null))
                .onFailure(ex -> startPromise.fail(ex));
        }
    }