Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey @Path for plural/single REST nouns in same class

Tags:

java

rest

jersey

I have a class this is annotated with @Path like so:

@Path("widgets")
@Produces(MediaType.APPLICATION_XML)
public class WidgetResource {

    @GET
    public Response getWidgets(@QueryParam("limit"))
    {
     //This class returns the plural noun, a list of widgets
    //...}

@GET
@Path("widget/{id}")
    public Response getWidgetById(@PathParam("id") long id)
    {
     //This class returns a single widget by id
    //...}

When I fire up a test client the localhost/widgets maps as expected, but when the getWidgetById method is mapped to localhost/widgets/widget/{id}. This is not what I want - I would like to have localhost/widgets and localhost/widget/{id}

I have tried omitting the @Path annotation at the class level, but that prevents Jersey from recognizing this class as a REST Resource (I tried both the ScanningResourceConfig and the ClassNameResourceConfig - both failed to load the class as a resource unless there was a @Path at the class level).

I guess a (ugly) workaround would be to split the methods between classes a WidgetResource class and a WidgetsResource class. I think this is a terrible solution since both of these methods share resources in the same class, but I really need the REST-ful localhost/widget (for a single entity) and localhost/widgets (for plural).

Am I missing something - is there some way for me to have Jersey pick up the class as a Resource class if I just @Path annotate the methods (I couldn't get it to work), if not can I force absolute mapping (@Path(/widget/{id})) or some relative mapping (@Path(../widget/id) - neither of those work in reality - just an analogy of what I'm after. Thanks!

like image 382
cschooley Avatar asked Jun 21 '12 17:06

cschooley


2 Answers

This part is about what you need:

Personally, I find your mapping strange and confusing. Just keep it like this:

@Path("widgets")
@Produces(MediaType.APPLICATION_XML)
public class WidgetResource {

  @GET
  public Response getWidgets(@QueryParam("limit")) {
   //This method returns the plural noun, a list of widgets
   // it's also possible to limit the number returned by
   // using a query parameter. You could easily implement
   // pagination by adding further query parameters like
   // 'offset', 'sortOrder', etc.
   //...
  }

  @GET
  @Path("{id}")
  public Response getWidgetById(@PathParam("id") long id) {
    //This method returns a single widget by id
    //...
  }
}

It seems natural to append the path to a collection with an ID to fetch an object from the collection. There's really no need to make it widgets/widget/{id}. The widget part is obvious and unnecessary.

Here's a really neat tutorial on RESTful APIs: "Teach a dog to REST" by apigee I think it's a really good video. The authors make a couple of good points. And here's a link to a longer version of the same presentation


This part is about what you want:

If you really want to keep the plural/singular dualism (which I really don't recomment), you can annotate your code like this: But it's really ugly

@Path("/")
@Produces(MediaType.APPLICATION_XML)
public class WidgetResource {

  @GET
  @Path("widgets")
  public Response getWidgets(@QueryParam("limit")) {
   //This method returns the plural noun, a list of widgets
  //...}

  @GET
  @Path("widget/{id}")
  public Response getWidgetById(@PathParam("id") long id) {
    //This method returns a single widget by id
    //...
  }
}
like image 64
toniedzwiedz Avatar answered Sep 20 '22 03:09

toniedzwiedz


My suggestion is to have your paths be: "widgets" and "widgets/id/{id}". Or if you knew you were never going to query by anything other than id, your second one could simply be "widgets/{id}".

I would not switch between plural and singular in your path. Since you accessing the same type of resource for both, your root should be the same. The second form just specifies it more -- a vectoring-based approach for getting more specific.

like image 29
Kevin Welker Avatar answered Sep 21 '22 03:09

Kevin Welker