B4J Question jServer "complex" URL mapping

MathiasM

Active Member
Licensed User
Hello

I'm trying to write a REST API in jServer. but i'm bumping into a wall.
Some context: I have a user endpoint, and a user can have transactions. Following basic RESt principles I do something like this:

GET /users -> Works srvr.AddHandler("/users"
GET /users/87 -> works srvr.AddHandler("/user/*")
GET /users/87/transactions -> Fails with srvr.AddHandler("/users/*/transactions")
GET /users/87/transactions/3 -> Also fails with srvr.AddHandler("/users"/*/transactions/*")

I get the same error on both cases:

java.lang.IllegalArgumentException: Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches: bad spec "/users/*/transactions"
The error is very clear, the * can only exist at the end of the path. But how would I accomplish what I want?
I tried delving into the Jetty API docs on pathmap here: https://www.eclipse.org/jetty/javadoc/current/org/eclipse/jetty/http/pathmap/PathMappings.html
But to be honest, I can't seem to find really useful information there. Must be my inexperience with Java docs in general.

Does anyone has clues or tips on how to construct my paths? What I'm trying to do is very common in API design, so I guess Jetty must support it in one way or another?

Thanks a bunch!
 
Last edited:

MathiasM

Active Member
Licensed User
I see wat you mean, you're the creator of Cuppify?! I have never checked it out, because I always try to do things without frameworks. But it seems that Jetty just cannot do what I want, so I'm going to check Cuppify out!
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Why are you using * like that? Is there another API that uses it that way? Why not /users/transactions to list all transactions for all users. /users/1/transactions for all transactions for user is 1. /users/1/transactions/3 for third transaction for user is 1.
 
Upvote 0

keirS

Well-Known Member
Licensed User
Longtime User
Why are you using * like that? Is there another API that uses it that way? Why not /users/transactions to list all transactions for all users. /users/1/transactions for all transactions for user is 1. /users/1/transactions/3 for third transaction for user is 1.

There are plenty. A URL path parameter is used to identify a resource and query parameters are used to filter the results.

So in the OP's example /users/87/transactions?datefrom=20190101&dateto=20190920 would return all the transactions for user 87 from the start of the year to today.

It is possible to handle this in Jetty by using a URL rewriter to either make the resource always appear at the end of the URL or make it a query parameter. AFAIK the B4J server library does not include the Jetty URL rewrite handler
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Last edited:
Upvote 0

FrostCodes

Active Member
Licensed User
I see wat you mean, you're the creator of Cuppify?! I have never checked it out, because I always try to do things without frameworks. But it seems that Jetty just cannot do what I want, so I'm going to check Cuppify out!
Cuppify is powered by Jetty, It is just all the hard work done for you :)
Jetty is a very powerful engine but you would only discover this if you take a deeper look into it
 
Last edited:
Upvote 0

MathiasM

Active Member
Licensed User
Why are you using * like that? Is there another API that uses it that way? Why not /users/transactions to list all transactions for all users. /users/1/transactions for all transactions for user is 1. /users/1/transactions/3 for third transaction for user is 1.

You're missing the point here. I never use a * in my URL. The * is only used as a wildcard for the Jetty server.
Eg: /users/* maps /users/1, users/2, users/n, users/84295494334349, users/qjfmoijcmoiqzjmoeqjmo, etc

If I would follow your logic, I would as much handlers as there are combinations in my database. The API would take a lot of time starting up, and everytime a new database record is created, a new handler would be needed. That's not the way to go, and that's why we use a ¨* as wildcard. a * can be replaced with everything in the URL, it's not meant to be a literal * like in that stackexchange question.

Cuppify is powered by Jetty, It is just all the hard work is done for you :)
Jetty is a very powerful engine but you would only discover this if you take a deeper look into it

I do understand this!

but it came to my mind that the problem I have is not really a problem.

/users/* also maps /users/3/transactions/4, so I can just get the url with .RequestURI, split it and find out that I need to go to the transaction class with the user id as parameter.
 
Upvote 0

FrostCodes

Active Member
Licensed User
You're missing the point here. I never use a * in my URL. The * is only used as a wildcard for the Jetty server.
Eg: /users/* maps /users/1, users/2, users/n, users/84295494334349, users/qjfmoijcmoiqzjmoeqjmo, etc

If I would follow your logic, I would as much handlers as there are combinations in my database. The API would take a lot of time starting up, and everytime a new database record is created, a new handler would be needed. That's not the way to go, and that's why we use a ¨* as wildcard. a * can be replaced with everything in the URL, it's not meant to be a literal * like in that stackexchange question.



I do understand this!

but it came to my mind that the problem I have is not really a problem.

/users/* also maps /users/3/transactions/4, so I can just get the url with .RequestURI, split it and find out that I need to go to the transaction class with the user id as parameter.
Yes that also works
 
Upvote 0
Top