How to make multiple #Path in a #GET in JAX-RS API? - java

So, in my Resource class I have the following:
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Carta> get() {
return repositorio.getAll();
}
#GET
#Path("{id}")
#Produces(MediaType.APPLICATION_JSON)
public Carta getById(#PathParam("id") int id) {
return repositorio.getID(id);
}
both works, one is a general get (will get all) and the other get by ID. I need to add a third get by String but I'm failing with the #params. I need to add this to the Resource class:
#GET
#Path("{nome}")
#Produces(MediaType.APPLICATION_JSON)
public List<Carta> getNome(#PathParam("nome") String nome) {
return repositorio.getString(nome);
}
if I comment the getById lines, my getByString works, the code is good, i just need to make both function at the same time, if it receives a number, it looks for an ID, if its a String it looks into name and description. Also, I wonder if it's better code practice to create more endpoints? Like /search/byid/xx and /search/byname/xxx instead of a general /search/xxx? Thanks.

Rather than creating a different endpoint, you should enhance List<Carta> get() to support filtering by card name.
The expected way to do that is to use the #QueryParam annotation like this:
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Carta> get(#QueryParam("name") String name) {
return repositorio.getCartas(name);
}
In the case of null name parameter, all Carta instances will be returned.

Related

Is there a way to order #Path in Quarkus

I currently have a problem similar to this but in quarkus-resteasy. I have looked around and I cannot find a way to order the paths. The endpoint for getAllNotifications() is never selected, all requests go to getModel():
#Get
#Path("/cars/{brand}/{model}")
#Produces(MediaType.APPLICATION_JSON)
public Response getModel(#PathParam("brand") String brand, #PathParam("model") String model) {
...
}
#Get
#Path("/cars/notification/all")
#Produces(MediaType.APPLICATION_JSON)
public Response getAllNotifications() {
...
}
Is there a way to prioritize either endpoint 1 or 2 like it was done here

Method not allowed when using regex in #Path with jersey

I am trying to provide endpoints that will listen on multiple versions, i.e /v1/test and /v2/test. In order not to duplicate my code, I use jersey's ability to use patterns in the #Path annotation.
Let's assume I want to provide a GET and a POST endpoint:
#Controller
#Slf4j
#Path("/")
public class TestController {
#GET
#Path("/v{version:[12]}/test")
#Produces(MediaType.APPLICATION_JSON)
public String test1(#PathParam("version") String version) {
System.out.println(String.format("GET /v%s/test called", version));
return "{\"foo\":\"bar\"}";
}
#POST
#Path("/v{version:[12]}/test")
#Produces(MediaType.APPLICATION_JSON)
public String test2(#PathParam("version") String version) {
System.out.println(String.format("POST /v%s/test called", version));
return "{\"foo\":\"bar\"}";
}
}
That works fine.
If I, however, try to use a specific path for the GET endpoints and use a pattern for the POST endpoint, I run into trouble.
Here the controller that would not work:
#Controller
#Slf4j
#Path("/")
public class TestController {
#GET
#Path("/v1/test")
#Produces(MediaType.APPLICATION_JSON)
public String test1() {
System.out.println("GET /v1/test called");
return "{\"foo\":\"bar1\"}";
}
#GET
#Path("/v2/test")
#Produces(MediaType.APPLICATION_JSON)
public String test2() {
System.out.println("GET /v2/test called");
return "{\"foo\":\"bar2\"}";
}
#POST
#Path("/v{version:[12]}/test")
#Produces(MediaType.APPLICATION_JSON)
public String test3(#PathParam("version") String version) {
System.out.println(String.format("POST /v%s/test called", version));
return "{\"foo\":\"barPOST\"}";
}
}
Doing GET /v1/test or GET /v2/test works fine, POST /v1/test however does not.
I get a 405 Method Not Allowed Exception.
As far as I got it the exception is thrown in the MethodSelectingRouter when it recognizes the path, but cannot find a method with the appropriate HTTP verb.
The issue seems to be that it picks the most specific path (/v1/test in my case) for which it does not know the POST verb.
Does anybody have an idea how to avoid this problem?
Cheers
PS: I am using spring boot with jersey (i.e. spring-boot-starter-web and spring-boot-starter-jersey) in version 1.5.2.RELEASE

Java REST: #GET and #PUT at the same path?

I have currently trying to learn the basics of Java REST, using JAX-RS.
Within the UserService class (near bottom) of this example there is both an #GET AND #PUT method with the same #path annotation:
#GET
#Path("/users")
#Produces(MediaType.APPLICATION_XML)
public List<User> getUsers() {
return userDao.getAllUsers();
}
and
#PUT
#Path("/users")
#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String createUser(#FormParam("id") int id,
#FormParam("name") String name,
#FormParam("profession") String profession,
#Context HttpServletResponse servletResponse) throws IOException {
User user = new User(id, name, profession);
int result = userDao.addUser(user);
if(result == 1) {
return SUCCESS_RESULT;
}
return FAILURE_RESULT;
}
How does the Program know which method to invoke, considering that they are both point at the same #path ?
Resource classes have methods that are invoked when specific HTTP method requests are made, referred to as resource methods. In order to create Java methods that will be invoked with specific HTTP methods, a regular Java method must be implemented and annotated with one of the JAX-RS #HttpMethod annotated annotations (namely, #GET, #POST, #PUT, and #DELETE).
For more info take a look at this example1 and example2
JAX-RS evaluates the HTTP method of the request and then calls the appropriate Java method in UserService.

How to reuse a REST methods in different resources?

Hi,
I am building a REST-api using Jersey and Java. I wonder if it is possible to reuse a method in many resources.
As an example If I have this code:
#Path("/users")
public class UserResource {
#GET
#Path("/{uid}/comments")
#Produces(MediaType.APPLICATION_JSON)
public List<Comment> getComments() {
return commentService.getOnEntity("User", uid);
}
}
and this:
#Path("/items")
public class ItemResource {
#GET
#Path("/{uid}/comments")
#Produces(MediaType.APPLICATION_JSON)
public List<Comment> getComments() {
return commentService.getOnEntity("Item", uid);
}
}
Is it possible to reuse the code for specifying the method "/{uid}/comments/" so I do not need to write it in every resource that is going to need it?
I guess I could extend a CommentResource with the method, but the I can only add one set of methods. If I use Interface I could specify more than one set of methods but would have to rewrite the code inside the methods in every resource.
Edit
After a tips from #thomas.mc.work I rewrote my code using a sub resource. It is better than the first solution since I get all methods from my sub resource and it only takes 4 lines of code per resource. This is how it looks like:
#Path("/users")
public class UserResource {
#Path("/{uid}/comments")
public CommentSubResource getCommentSubResource(#PathParam("uid") String uid) {
return new CommentSubResource("User", uid);
}
}
and this:
#Path("/items")
public class ItemResource {
#Path("/{uid}/comments")
public CommentSubResource getCommentSubResource(#PathParam("uid") String uid) {
return new CommentSubResource("Item", uid);
}
}
and this:
public class CommentSubResource {
private String entity;
private String entityUid;
public CommentSubResource(String entity, String entityUid) {
this.entity = entity;
this.entityUid = entityUid;
}
#GET
#Path("/")
#Produces(MediaType.APPLICATION_JSON)
public List<Comment> getComments() {
return commentService.getOnEntity(entity, entityUid);
}
#DELETE
#Path("/")
#Produces(MediaType.APPLICATION_JSON)
public List<Comment> deleteComment(#PathParam("uid") String uid) {
return commentService.delete(uid);
}
}
This is much better. I have an idea to use java 8 and default implementation interfaces to be able to just implmenet an interface to get the functionality, but I am not sure if I am able to determine which resource the default implemented method is called from.
Edit
After some laboration I think subresources is the way to go, even if it´s not (according to me) the perfect solution.
There is a similar feature called "Subresource Locators". You can decide in runtime which Resource is selected to process the request that is matching your JAX-RS method.

Finding a method exists in rest service or not in Java

Hi i am new to Rest Service in Java. First i want to explain my problem and then at the end i will be asking question.
I am using Mozilla rest CLIENT. My rest class looks like:
#Path("/api1")
public class RestService {
#POST
#Path("/v1")
#Consumes("application/json")
#Produces("application/json")
public String v1(String json){
//Some code here
}
#POST
#Path("/v2")
#Consumes("application/json")
#Produces("application/json")
public String v2(String json){
//Some code here
}
}
Now in this code i have two functions.
To access v1, call will be:
http://localhost:8080/project_name/package/api1/v1
To access v2 call will be:
http://localhost:8080/project_name/package/api1/v2
Question:
Now in my rest service class i want to add a patch of code which detects that whether any function which has been called either v1,v2 or v3 exists in this service or not?
Can i do this? Or anyother way to do this?
Thanks
Well, you could add a wildcard response:
#POST
#Path("/{what}")
#Consumes("application/json")
#Produces("application/json")
public String v2(String json, #PathParameter("what") String what){
return "The path "+what+" does not exist.";
}
However, since the user will never see the direct responses, you can answer with a customized 404:
#POST
#Path("/{what}")
#Consumes("application/json")
#Produces("application/json")
public Response v2(String json, #PathParameter("what") String what){
return Response.status(Status.NOT_FOUND).entity("The path "+what+" does not exist.");
}
This way you can also detect on the client side when something is incorrect.
The best approach for you is to add a fallback response. That will be called when somebody tries to access any non existing WS method.
#RequestMapping(value = {"*"})
public String getFallback()
{
return "This is a fallback response!";
}

Categories