Ok, so I am building a RESTful service in Java using Jersey.
I have implemented the POST which works wonderfully, which creates a new row in the Category table in my Database. Now when I try to do the DELETE, I pass it the same row in JSON, but it returns a "400: Bad Request - the request cannot be fulfilled due to bad syntax".
I am confused, since the JSON is copied and pasted from the result I get when I do a GET on that specific category.
Here is the relevant code:
#Path("/categories/")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class CategoryResource {
#POST
public Response addCategory(Category category, #Context UriInfo uriInfo)
{
JSONArray json_array = category_service.addCategory(category);
URI uri = uriInfo.getAbsolutePathBuilder().path(category.getCategory_name()).build();
return Response.created(uri)
.status(Status.CREATED)
.entity(json_array.toString())
.build();
}
#DELETE
public Response deleteCategory(Category category)
{
System.out.println("Category = " + category.toString());
category_service.deleteCategory(category);
return Response.ok().build();
}
The system.out.println() is never executed because it seems like it fails to do the encoding of the category. The Category class is here, replete with the usual getters and setters:
#XmlRootElement
public class Category {
private int category_id;
private String category_name;
private boolean child;
private int parent_id;
private boolean category_state;
private String category_reason;
public Category() {
}
The JSON that is being passed in the raw looks like this:
{
"category_id": 1,
"category_name": "tennis",
"child": true,
"parent_id": 4,
"category_state": true,
"category_reason": "I Like Tennis"
}
Note that this has been copied and pasted from the result of the GET....
So as was made clear in the comments by peeskillet, with a DELETE you don't give any body.
Related
I have a POST endpoint which accepts a JSON as request body.
#Path("/drink")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class DrinkResource {
#POST
public Drink getDrink(Fruit fruit) {
return new Drink(fruit.getName());
}
}
The request body is supposed to be deserialized into this POJO :
public class Fruit {
private final String name;
#JsonCreator
public Fruit(#JsonProperty("name") String name) {
this.name = name;
}
public String getName() {
return name;
}
}
I'm using Jackson for the deserialization.
Is it possible to make the deserialization fail when the JSON in the request body has duplicate keys ?
For example, if the request body looks like this : {"name" : "banana", "name" : "orange"}, I would like to get a 500 status code or another kind of error instead of having the json deserialized with the last property.
Basically, I'm looking for a solution with the same logic as the JsonParser.Feature.STRICT_DUPLICATE_DETECTION with the ObjectMapper but for a POST endpoint.
I'm also using quarkus so I don't know if there is a property for this. Something similar to quarkus.jackson.fail-on-unknown-properties=true but for the duplicate properties.
Add the following:
#Singleton
public class MyCustomizer implements ObjectMapperCustomizer {
#Override
public void customize(ObjectMapper objectMapper) {
objectMapper.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
}
}
If you do, the ObjectMapper that Quarkus uses will throw a JsonParseException thus leading to a HTTP 400 response.
For some reason java can't map DTO with requestBody and all values are default ones, as for request it works, with payload for ex. "{"productId":1,"commitment":6,"returnMonths":"2"}"
DTO
#Data
public class Request {
private int productId;
private int commitment;
private String returnMonths;
// contructers
}
Controller :
#PostMapping(value = "/calculate", consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public String calculatePrice(#RequestBody Request request) {
productService.calculatePrice(request);
return "Success";
}
front request:
submit: async function() {
let request = {
productId: this.productSelected,
commitment: this.optionSelected,
returnMonths: this.input
};
let data = await getCalculation(request);
console.log(data);
}
DTO maps as:
productId : 0
commitment : 0
returnMonths : null
Tried an exact copy of your code and it worked when tested with Postman. This makes me think it's either something to do with the FE or maybe some issue in the service. I'd check if the Frontend really sends the data.
Try to annotation Request class with #AllArgsConstructor like:
#AllArgsConstructor
#Data
public class Request {
private int productId;
private int commitment;
private String returnMonths;
}
If your request body contains properties that is date such as LocalDateTime, make sure to format it in your DTO using #JsonFormat(pattern="") respecting the input value.
I have this code using Angular 4 HttpClient, supposed to communicate with a simple RESTful JAVA web service and get a JSONstring back:
this.client.post('http://localhost:8080/ToDoService/rest/service/create', {id: 'foo', todo: 'bar'}).subscribe((data) => {
console.log("Got data: ", data);
}, (error) => {
console.log("Error", error);
})
It's not working. What I mean is that the id and todo parameters are not getting passed to the REST backend.
At the other hand, if I change above code to:
this.client.post('http://localhost:8080/ToDoService/rest/service/create?id=foo&todo=bar', '').subscribe((data) => {
console.log("Got data: ", data);
}, (error) => {
console.log("Error", error);
})
Everything works fine, but I'm sure the second snipped is wrong. It just looks wrong.
Could you give me a push and point my mistake?
P.s
The JAVA backend:
#Path("/service")
public class Rest extends Application{
#POST
#Path("/create")
public Response printMessage(#QueryParam("id") String userId, #QueryParam("todo") String toDo) {
JSONObject result = new JSONObject();
result.put("id", userId);
result.put("todo", toDo);
return Response.status(200).entity(result.toString()).build();
}
}
You're mapping QueryParams, you need to map that payload to either a Map or an Object:
class PayLoad {
private String id;
private String todo;
// Getter and Setters
}
#Path("/service")
public class Rest extends Application{
#POST
#Path("/create")
public Response printMessage(#RequestBody PayLoad payload) {
JSONObject result = new JSONObject();
result.put("id", payload.getId());
result.put("todo", payload.getTodo());
return Response.status(200).entity(result.toString()).build();
}
}
Hope this helps!
First of all, looking at the MyKong tutorial you can see that #QueryParam accepts parameters sent in the URL. That is a first problem here. Back to the main point.
I am not an expert in Angular 4, but I think the problem lies deeper in your architecture. You are sending to your backend:
{id: 'foo', todo: 'bar'}
and expect in your Java:
#QueryParam("id") String userId, #QueryParam("todo") String toDo
You pass an object and expect in your Java backend two strings. If you want to get your object, you might create this kind of class:
public class JsonWrapper {
private String id;
private String todo;
// Classic constructor and setters
}
Then, in your service:
#Path("/service")
public class Rest extends Application {
#POST
#Path("/create")
public Response printMessage(#RequestBody JsonWrapper wrapper) {
JSONObject result = new JSONObject();
result.put("id", wrapper.getId());
result.put("todo", wrapper.getTodo());
return Response.status(200).entity(result.toString()).build();
}
}
If the JsonWrapper does not work, I think a Map can do the trick, too.
I have the following JSON that will be passed as part of a HTTP request, in the message body.
{
"names": [
{
"id":"<number>",
"name":"<string>",
"type":"<string>",
}
]
}
My current REST handler is below. I am able to get the Id and `Version that is passed in as path params, but I am not sure how to retrieve the contents on the message body?
#PUT
#Path("/Id/{Id}/version/{version}/addPerson")
public Response addPerson(#PathParam("Id") String Id,
#PathParam("version") String version) {
if (isNull(Id) || isEmpty(version)) {
return ResponseBuilder.badRequest().build();
}
//HOW TO RECIEVE MESSAGE BODY?
//carry out PUT request and return DTO: code not shown to keep example simple
if (dto.isSuccess()) {
return Response.ok().build();
} else {
return Response.serverError().build();
}
}
Note: I am using the JAX-RS framework.
You just need to map your name json to a POJO and add #Consumes annotation to your put method, here is an example:
#PUT
#Consumes("application/json")
#Path("/Id/{Id}/version/{version}/addPerson")
public Response addPerson(#PathParam("Id") String Id,
#PathParam("version") String version,
List<NamObj> names) {
I assume you are trying to retrieve a list of elements if is not the case just use you POJO as it in the param.
Depending on what json library are you using in your server you may need to add #xml annotation to your POJO so the parser could know how to map the request, this is how the mapping for the example json should look like:
#XmlRootElement
public class NameObj {
#XmlElement public int id;
#XmlElement public String name;
#XmlElement public String type;
}
Jersey doc: https://jersey.java.net/documentation/latest/user-guide.html#json
#cosumes reference: http://docs.oracle.com/javaee/6/tutorial/doc/gilik.html#gipyt
I'm working on adapting angular-ui-tree to persist the tree structure in a one-to-many entity model. The piece I am missing is how to have Spring/Jackson interpret the following POST body
data: "{
"id":1.7976931348623157e+308,
"name":"New Category -- Need Name",
"parent":6,
"type":"create"
}"
that is serialized and delivered using a $http service method in Angular:
$http.post("/rest/category",
{data: angular.toJson(updateData)}
)
.success(function(data, status, headers, config){
return [data, status];
})
.error(function(data, status, headers, config){
return [data, status];
})
Right now, I only get error 405s with the address, with the return value stating that
Request method 'POST' not supported
So, I modified the controller below to take in a DummyCategory object from the RequestBody:
#RequestMapping(value = "/rest/category", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public List<Category> createCategory(#RequestBody DummyCategory data ){
log.info("Start creating category " + data);
}
which is this entity:
#JsonDeserialize(using = DummyCategoryDeserializer.class)
public class DummyCategory {
private String type;
private String name;
private Long id;
private int parent;
//getters and setters
}
and corresponding DummyCategoryDeserializer class:
public class DummyCategoryDeserializer extends JsonDeserializer<DummyCategory> {
#Override
public DummyCategory deserialize(JsonParser jp, DeserializationContext ctx) throws IOException {
String tempData = jp.getText();
DummyCategory dummyCategory = new DummyCategory();
return dummyCategory;
}
}
Since I am very new at this, my goal is to have a debugger breakpoint set at the deserializer method and work my way through the properties. However, after making these custom modifications, the $http service is still returning 405s on execution, and the breakpoints are not being hit.
I know that the server is functional, because all GET requests are returning expected values.
If you want to see the actual source code for this question, it is available on the category-taxonomy branch. The new deserializer classes are within /models and /utils