5

I want to create a URL structure for my Vert.x Web powered API that makes it clear how some entities are "contained" inside other entities and how you "traverse the entity path" to find child entities, so I'm thinking of using something like this to address a "grand child" (I don't expect anything deeper than a grand child):

GET /entity/:parent_id/sub-entity/:child_id/subsub-entity/:grandchild_id

So normally my Router configuration will look something like this:

router.get("/entity/:parent_id/sub-entity/:child_id/subsub-entity/:grandchild_id")
    .handler(r -> {
       HttpServerRequest req = r.request();
       Minipart p = Entities.get(req.getParameter("parent_id"))
           .getPart(req.getParameter("child_id"))
           .getMinipart(req.getParameter("grandchild_id"));
       // do something with p
    });

When I add a lot of operations (each entity class at each level has catalog and create operations, and each level entity instance has get, update and delete operations, as well as a few other tidbits), my router class gets really large.

I was thinking of using sub-routers to offload the sub-entity management down the line, so the Entities Router configuration might do:

router.mountSubRouter("/entity/:parent_id/sub-entity", PartsRouter.init(vertx));

and then PartsRouter can do:

router.get("/:child_id").handler(r -> {
    String parentEntityId = r.request().getParameter("parent_id");
    Entity parent = Entities.get(parentEntityId);
    String myid = r.request().getParameter("child_id");
    Part myself = parent.getPart(myid);
    // do something with myself
});

But when I do try that and try to access the sub-router operations, I get a 404 error from Vert.x...

Update:

Apparently Vert.x explicitly does not support this - it threw an exception that my wrapper code just logged and ignored, saying:

java.lang.IllegalArgumentException: Can't use patterns in subrouter mounts

So, is there another way to achieve what I'm trying to do (split a large router configuration into a proper class hierarchy)?

Guss
  • 30,470
  • 17
  • 104
  • 128

1 Answers1

1

I can image 2 ways of solving your problem:

The first one would be to have a initial handler that processes the common part of the request and calls next so the following one will continue where the first stopped e.g.:

router.route("/entity/:parent_id/sub-entity", ctx -> {
  // common part here...
  ctx.next();
});

And then:

router.route("/entity/:parent_id/sub-entity/:child_id", ctx -> {
  String parentEntityId = r.request().getParameter("parent_id");
  Entity parent = Entities.get(parentEntityId);
  String myid = r.request().getParameter("child_id");
  Part myself = parent.getPart(myid);
  // do something with myself
});

Alternatively you can use internal redirects, so you handle the initial code as before but instead of calling next() you redirect to another URL. In that case you should store in the context what you want to reuse since the request will be restarted in the new location.

Paulo Lopes
  • 5,845
  • 22
  • 31
  • I didn't know about `ctx.next()`, and that is useful, but your solution still doesn't solve the need to have the full path with all arguments in every single route registration, I currently have about 20 such API calls and I expect to have at least 4 times that. – Guss Sep 23 '16 at 14:45
  • If your issue is the repetition of the request path you can use the `reroute()` method and point it to a generic handler or since the path is a plain string use a String constant and concatenate the difference on each handler. – Paulo Lopes Sep 26 '16 at 07:25
  • I eventually implemented something like your original answer. What I did is to implement a class that generates the `route()` path automatically based on a nested set of classes where each calls the API to add itself on top of a "parent route". This is a bit complex but useful and expressive (I'll see about releasing it as open source), though I sure wish Vert.x would have prevented that hassle and implemented patterns in `mountSubrouter()`. There is definitely a missing API here. – Guss Dec 25 '16 at 14:51
  • If any one is still interested in a programmatic solution, I've released a library that handles that as part of a larger pattern. Its open source and you can find it here: https://github.com/GreenfieldTech/irked – Guss Jul 20 '17 at 19:23