Java: PUT request without id getting submitted as POST - java

I have create and update api calls for same entities. If user send a PUT request with no object id, controller accepts it as a POST request and creates a new object. How can I prevent that?
#POST
#Consumes({MediaType.APPLICATION_XML})
#Produces({MediaType.APPLICATION_XML})
public Response create(Entity entity){}
#PUT
#Path("/{id}")
#Consumes({ MediaType.APPLICATION_XML })
#Produces({ MediaType.APPLICATION_XML })
public Response update(#PathParam("id") int id,Entity entity){}
Is there a way to make request parameter required for update? That may resolve the issue as well.

Add a RegEx pattern from your #Path.
Syntax:
#Path("/{" variable-name [ ":" regular-expression ] "}")
Example:
#Path("/{id: <replace_with_reg_exp>}")

Related

How can I determine the order of parameters for x-www-form-urlencoded in Microprofile RestClient?

Use Case
I have following rest client
#RegisterRestClient(configKey = "service")
public interface Service {
#POST
#Path("Invoice")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
Response request(#QueryParam("instance") String instance, #BeanParam Input input);
}
Input is a class which is a POJO including properties like
public class Input {
#FormParam("title")
public String title;
#FormParam("description")
public String description;
Problem
The request to the API is working fine, but in my case, the order of properties does matter (The reason behind that is something, I cannot answer at the moment, sorry).
So sending title=Test&description=Testdescription is different to description=Testdescription&title=Test.
Other solutions I have tried
With Form instead of POJO: No data is send to the server
#POST
#Path("Invoice")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
CustomResponse requestForm(#QueryParam("instance") String instance, #BeanParam Form form);
With Entit<Form>: No data is send to the server
#POST
#Path("Invoice")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
CustomResponse requestForm(#QueryParam("instance") String instance, #BeanParam Entity<Form> form);
Assumption
I found out, that org.jboss.resteasy.client.jaxrs.internal.proxy.processors.FormProcessor is using a HashMap internally. I think that is exactly the problem, because there is no guaranteed order. Is my assumption correct?
Question
How can I work around that and always provide the same order for the API using the Microprofile Rest Client.
Workaround
It works with a org.jboss.resteasy.client.jaxrs.ResteasyClient invoking like
Response response = target
.request(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_FORM_URLENCODED)
.post(Entity.form(form));
It's works for me, see:
#POST
#Path(value = "/auth/realms/{realm}")
#Consumes(APPLICATION_FORM_URLENCODED_VALUE)
AuthenticateResponse authenticate(#PathParam("realm") String realm, MultivaluedMap<String,?> params);
Try to use MultivaluedMap

Dropwizard Rest API endpoint manipulation

I have a dropwizard application to POST/GET query information. I have a #POST method that populates an arrayList with my query and its' 11 parameters. For brevity, I cut the example down to only show 3 parameters.
#Path("/query")
public class QueryResource
#GET
#Produces(MediaType.APPLICATION_JSON)
#Timed
public List<Query> getQueries() {
List<Query> queries = new ArrayList<Query>();
logger.info("Calling get queries with {} method.");
queries.add(new Query("b622d2c6-03b2-4488-9d5d-46814606e550", "eventTypeThing", "action"));
return queries;
I can send a get request through ARC and it will return successful with a json representation of the query.
I run into issues when I try to make a #GET request on the specific queryId and return a specific parameter of it. As such,
#GET
#Path("/{queryId}/action")
public Response getAction(#PathParam("queryId") String queryId, #PathParam("action") String action){
logger.info("Get action by queryId {}");
String output = "Get action: " + action;
return Response.status(200).entity(output).build();
On the rest client I make a get request to https://localhost/query/b622d2c6-03b2-4488-9d5d-46814606e550/action
I'm expecting that to return the action type of that specific queryId, but instead is returning null.
You did not declare "action" as a proper param in the #Path annotation of the method. You need to change that to:
#Path("/{queryId}/{action}")

InitBinder for method

I have a rest controller:
#RestController
public abstract class CrudController {
#RequestMapping(
path = "delete",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON,
consumes = MediaType.APPLICATION_JSON)
public ResponseEntity<ResponseDTO<Void>> delete(
#RequestBody IdDTO request,
#RequestHeader("X-auth-token") String token,
BindingResult bindingResult
) {
//delete logic
}
#RequestMapping(
path = "read",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON,
consumes = MediaType.APPLICATION_JSON)
public ResponseEntity<ResponseDTO<DTO>> read(
#RequestBody IdDTO<User> request,
#RequestHeader("X-auth-token") String token,
BindingResult bindingResult
) {
//read logic
}
}
I wanted to add Spring Validation. It is obvious that for read method and for delete method should be different validators. I want to know it it possible to make two #InitBinder one for read and another for delete?
I think you're not quite familiar with usage of BindingResult. It is used in process of binding object from request to Java object.
It searches the class validator, or uses validation annotations used on class' fields. Object you want to bind needs to be annotated with #Valid.
For example:
#PostMapping
public ResponseEntity<Note> addNote(#Valid Note note, BindingResult result) {
if(result.hasErrors())
return ResponseEntity.badRequest().build();
noteService.save(note);
return ResponseEntity.ok(noteService.getNoteById(note.getId()));
}
What you're trying to do is validate something, but not quite bind it.
I also suggest using different http methods for delete and read(GET) in the same path rather than POST method in different paths.

how can extract parameter from #QueryParam

#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Path("/categories")
public Response getAllCategories(#QueryParam(value = "code") String country_code) {
return userService.getAllCategories(country_code);
}
my url:"/user/categories?code=+91"
how can i extracting request parameters "+91" in RESTful web service.
#QueryParam is JAX-RS. If you want to use Spring, the appropriate annotation would be #RequestParam:
public Response getAllCategories(#RequestParam("code") String country_code) {
...
}
But of course, #Path, etc. are also not Spring, so perhaps you should ask yourself if you actually want to use Spring...

Receiving JSON Response

I am trying to receive a JSON response with Jersey but it is always sending null. Here is my service code:
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML,
MediaType.TEXT_XML })
#Path("/songs/")
public Room AddSong(#PathParam("json") String Info) {
Song newSong = new newSong();
newSong.addSong(Info);
return newSong;
}
In this case, "Info" is always null. I receive a 200 response from the server so I know the JSON is being sent. The only other thing im not sure is, should I sent JSON in UTF-8?
First of all, you need to use #PathParam correctly. You need to specify {json} in your url. Look at the example
UPD: It's just occurred to me, you in your case you don't need to use #PathParam at all. Just put it away and it should work.
Path parameters take the incoming URL and match parts of the path as a parameter. By including {name} in a #Path annotation, the resource
can later access the matching part of the URI to a path parameter with
the corresponding "name". Path parameters make parts of the request
URL as parameters which can be useful in embedding request parameter
information to a simple URL.
#Path("/books/{bookid}")
public class BookResource {
#GET
public Response invokeWithBookId(#PathParam("bookid") String bookId) {
/* get the info for bookId */
return Response.ok(/* some entity here */).build();
}
#GET
#Path("{language}")
public Response invokeWithBookIdAndLanguage(#PathParam("bookid") String bookId, #PathParam("language") String language) {
/* get the info for bookId */
return Response.ok(/* some entity here */).build();
}
}
In your rest code argument Info takes value from #Path("/songs/{json}") but you have specify #Path("/songs/") so json will always be null
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML,
MediaType.TEXT_XML })
#Path("/songs/")
public Room AddSong(#PathParam("json") String Info) {
Song newSong = new newSong();
newSong.addSong(Info);
return newSong;
}
You do like this and then everything will be fine :
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML,
MediaType.TEXT_XML })
#Path("/songs/{json}")
public Room AddSong(#PathParam("json") String Info) {
Song newSong = new newSong();
newSong.addSong(Info);
return newSong;
}
For more info refer JAX-RS Parameters
You do not need the #PathParam as the JSON contents should be in the POST body. You have declared the return type to be Room, but are you not trying to return type Song? Assuming this is a simple JSON wrapped string, the contents are in the POST body, and you want Song returned in the 200 OK then you can try this:
#POST
Consumes(MediaType.APPLICATION_JSON)
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
#Path("/songs/")
public Song AddSong(String Info) {
Song newSong = new newSong();
newSong.addSong(Info);
return newSong;
}
Optionally, if you want to use a JSON representation of Song in the API, you can replace String Info with Song newSong and then specific Song in the POST body.

Categories

Resources