1

I have an issue regarding the differentiation between two Rest methods that have the same amount of path parameters:

@GET
    @Path("image/{ratio}/")
    @Produces("image/png")
    @PermitAll
    public Response getImageMe(HttpServerRequest request, @PathParam("ratio") String ratio) {
//Do something
}

@GET
    @Path("image/{user}/")
    @Produces("image/png")
    @PermitAll
    public Response getImageUser(HttpServerRequest request, @PathParam("user") String user) {
//Do something
}

Sadly they both have to be Strings as the ratio can be either "64" or "64x64". I tried using an Annotation to validate the input but even with valid input for one, it is still forwarded to the other method.

I am currently thinking about some sort of Frontcontroller that would look something like this:

@GET
    @Path("image/{ratioOrUser}/")
    @Produces("image/png")
    @PermitAll
    public Response oneParamWrapper(@PathParam("ratioOrUser") String ratioOrUser) {
//validate and forward 
}

Is that the preferred way to do this or even the only way or are there other, better ways?

1 Answer 1

3

This is a matter of technical constraint and the cost of trying to overcome it (and whether it's worth it).

Generally speaking, a given path should go to a given endpoint.

However, some API frameworks are able to add additional filtering on input data types, making them able to differentiate between e.g. /path/{integer} and /path/{guid}, which enables you to write different endpoints for the different input data types.

But there is a ceiling to how much your framework will be able to infer. For example, if the options are int and string, any integer can also be parsed as a string, so it's less clear whether the framework will be able to understand your intentions.
And even if it can parse your intentions in the right order, you would be effectively unable to get to the right endpoint when the intended string value happens to (coincidentally) also be a valid integer.

Then we get to having interchangeable types, such as path/{user guid} and path/{image guid}. Note that I'm using GUID here, specifically to not get distracted by cases where both images and users have a resource with the same key value.

Technically, you could write a custom interpreter that actually checks the database to confirm whether this GUID is found in the users or images table. From a technical perspective, that is possible, but I find this way too involved for what is supposed to be a very simplistic API path pattern matching.

Sadly they both have to be Strings as the ratio can be either "64" or "64x64"

This, however, may be a saving grace. I'm speaking from experience with the .NET Api Framework, I assume this feature also exists for Java.

It is possible to write a custom value parser which specifically looks for the string values "64" and "64x64", and when found converts these to a custom Ratio object that you've defined. Any other strings would then not be accepted by this parser, leaving you open to reroute to the other endpoint.


The conclusion here is that there is a disconnect between what is technically possible and what it considered to be a good approach. This may vary based on circumstances.

In my personal order of preference:

  1. Use two distinct paths, e.g. /image/user/{...} and /image/ratio/{...}, and have two separate endpoints
  2. Use query parameters, e.g. /image?user={...} and /image?ratio={...}, and have a single endpoint which split off towards separate business logic based on which query param was entered
  3. Write a custom value mapper in your API framework that detects ratio values and routes them to the Ratio-based endpoint, and otherwise falls back to the string-based endpoint
  4. Write a single endpoint that takes in any arbitrary value, and have your business logic figure out what this value can be used for.
1
  • I thought this might be the answer to this. Sadly 1 & 2 are not possible due to backward compatibility. 3 Is not possible in the framework, I think. But thank you anyway :)
    – SirHawrk
    Jul 29 at 6:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.