Testing Spring MVC POST with IntelliJ REST client causes 415 - java

I'm developing an application in Java/Spring MVC and have no problem with testing my GET methods. The problem occur then I try to test the POST using #RequestBody.
The error:
HTTP 415 The server refused this request because the request entity is in a format not supported by the requested resource for the requested method.
I created a simple test to show my problem:
#RestController
#RequestMapping("/test")
public class ConcreteTestController implements TestController {
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.OK)
#Override
public void add(#RequestBody Dummy dummy) {
System.out.println(dummy);
}
#RequestMapping(method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.OK)
#Override
public Dummy get() {
Dummy dummy = new Dummy();
dummy.setName("apa");
return dummy;
}
}
The Dummy class is very simple:
public class Dummy {
private String name;
public Dummy() {}
// Omitted setters and getters.
}
The jsonresponse from the GET looks like this:
{"name":"apa"}
I'm starting the IntelliJ REST client and using the json above as request body. I've tried using both application/json and / under Accept in the header with no difference in result.
Any idea what could cause this? I'm stuck and would appreciate help.

By default you have to add Content-Type manually in the REST client in IntelliJ. I had forgotten to do so and to set it to application/json. After having done so it is working fine.

Related

How can I get my spring boot controller to read the body of my http request to an object if the http request has content type urlencoded?

I am new to spring and spring boot and have set up a simple controller that can read http requests to an object if there is a header set setting the content-type to application/json.
However, when I do not set the content type in a header, this does not work and I get the error: "Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported". I understand that at no point have I told the controller that I actually want the it to read the body as JSON rather than as urlencoded and I'm looking for a way of doing this.
I have experimented with the #RequestBody, #RequestParam and #ResponseBody annotations but so far have had no luck.
I have also looked at overriding the WebMvcConfigurer.configureContentNegotiation method by setting default and other media-types but am less clear on what I am doing here.
Here is my simple controller in its current form
public class GreetingController {
#RequestMapping(value = "/greeting",
method = RequestMethod.POST)
public Greeting postGreeting(#RequestBody Greeting body) {
return new Greeting(body.getId(),"hello " + body.getContent());
}
}
Here is the constructor for my greeting class for reference:
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
The body of my request is '{"id":10, "content": "world"}'
Ideally, I would like to find a way to be able to process an http request with no content type header set (so presumably defaulting to form-urlencoded) as JSON so that there is less to think about when setting up the post request and the controller is less brittle.
Try this:
#RestController
public class GreetingController {
#RequestMapping(value = "/greeting",
method = RequestMethod.POST)
public HttpEntity<String> postGreeting(#RequestBody Greeting body) {
//SETGREETING()
return new HttpEntity<String>("data has been saved");
}
}
And don't forget to accept application/json header.
Try below code
import org.springframework.web.bind.annotation.ModelAttribute;
public class GreetingController {
#RequestMapping(value = "/greeting",
method = RequestMethod.POST)
public Greeting postGreeting(#ModelAttribute Greeting body) {
return new Greeting(body.getId(),"hello " + body.getContent());
}
}

HTTP Status 415 – Unsupported Media Type when doing POST request on Spring MVC

I am trying to send a post request on a simple Spring MVC web app and use RequestBody in my controller to convert the JSON into a Java Object but for whatever reason, I keep getting HTTP Status 415 – Unsupported Media Type. I have spent a lot of time trying to find a solution to this but nothing seems to be working.
The get method in my Controller seems to be working fine. This is my original code
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
#Controller
#RequestMapping(value = "/users", method = RequestMethod.POST)
public class MyControllerAgain {
#RequestMapping(method = RequestMethod.POST, consumes = "application/json")
public void handleJson(#RequestBody Contact c) {
System.out.println(c);
}
#RequestMapping(method = RequestMethod.GET, consumes = "application/json")
public void handleGet() {
System.out.println("a");
}
}
This is my Contact
public class Contact {
int id;
public String name;
public int number;
public Contact(){}
// Getters and setters
}
I am sending a request with Postman and this is what it looks like
POST /users HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Accept: application/json
Cache-Control: no-cache
Postman-Token: 511c9e03-4178-380d-58f8-db24a3245b9e
{
"id":1,
"name":"something",
"number":1
}
I have also tried including Jackson dependencies in my pom.xml .
I have tried altering consume value in #RequestMapping annotation and I have tried all combinations of headers accept and Content type in my request.
Also, If I use #ModelAttribute instead of #RequestBody, then everything works fine except all the fields in Contact class are null.
Here is the github link - https://github.com/Sanil2108/test_springmvc
To me it looks like that the jpa anotations are messing up the json deserialization.
The error returned from the spring server could be misleading.
Try using plain object with setters and getters and see if this changes anything.
You should search for some exceptions in the logs.
RequestMapping annotation not only has the consumes but also produces.
But to avoid all these settings for HTTP REST, you can use RestController annotation and GetMapping, PostMapping etc..
You can find an example in my github
Add a mapping to the handleGet method, for example:
#RequestMapping(value = "/get", method = RequestMethod.GET, consumes = "application/json")
public void handleGet() {
System.out.println("a");
}
--UPDATE--
Remove the consumes = "application/json" part from you GET call. It sees that both requests that listen to "/users" can consume json data, but one is a GET and the other one is a POST.
--2nd UPDATE--
This will definitely work. Tested.
#RestController
#RequestMapping(value = "/users", method = RequestMethod.POST)
public class ContactController
{
#RequestMapping(method = RequestMethod.POST, consumes = "application/json")
public void handleJson(#RequestBody Contact c)
{
System.out.println(c);
}
}
Tried everything but couldn't it to work. Maybe I was making a silly mistake somewhere or there was something seriously wrong with my configuration. Anyway, I tried to make it work with Spring boot and it worked fine. For anyone who is interested, Here is the github link - https://github.com/Sanil2108/spring_hibernate/tree/master/spring_boot1
Also, thanks to everyone who tried to help!

Can I create multiple HTTP POST methods with same request mapping with different requestbody

Can I create multiple HTTP POST methods with same request mapping with different requestbody
#RequestMapping("api/v1/")
#RequestMapping(value = "test" ,method = RequestMethod.POST)
public RObjet create(#RequestBody RBody rbody)
{
// do some process...
}
#RequestMapping("api/v1/")
#RequestMapping(value = "test" ,method = RequestMethod.POST)
public RObjet2 create2(#RequestBody RBody2 rbody)
{
// do something.
}
Is this possible.? How do we handle this in spring boot.
Yes, you can use POST Http Method for the same end point URI with different request body and also you could get different responses. One way to achieve this, is mapping requests using end point URI + Headers
e.g.
#RestController
#RequestMapping("/api/bills")
public class BillingController {
#RequestMapping(method = RequestMethod.POST, headers = "action=add-bill")
public BillId addBill(#Valid #RequestBody BillingData data) {
//Some code
}
#RequestMapping(method = RequestMethod.POST, headers = "action=delete-bill-by-id")
#ResponseStatus(code = HttpStatus.NO_CONTENT)
public void removeBill(#Valid #RequestBody BillId identifier) {
//Some code here to remove bill
}
}
In this case, both class methods in BillingController are mapped to the same HTTP Method (POST) and URI (/api/bills). The header action drives what class method in BillingController is going to be invoked once you point your post request to /api/bills
How to hit BillingController.addBill?
NOTE: I know that good REST API design dictates that if I want to delete records I should use DELETE method, however this sample was created only as reference to show how to use same URI/Method to handle 2 different end points.
You have to option for this.
it is possible with consumes field. You can use different consuming types.
You can user params field if you have in url.
#RequestMapping(value="/path", params="id")
public String test1(#RequestBody RBody body) {}
#RequestMapping(value="/path", params="name")
public String test2(#RequestBody RBody body) {}

How to call a #RestController with #RequestBody?

I have a simple servlet as follows:
#RestController
public class TestServlet {
#RequestMapping(value = "/test1")
public String test1() {
return "test1";
}
#RequestMapping(value = "/test2")
public String test2(#RequestBody TestClass req) {
return "test2";
}
public static class TestClass {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
But only the servlet not receiving parameters is working:
Works: http://localhost:8080/test1
Doesn't work: http://localhost:8080/test2?value=1234
org.springframework.http.converter.HttpMessageNotReadableException:
Required request body is missing: public java.lang.String
Why is the #RequestBody annotation not working? Am I missing an important piece?
One of the differences between #Controller and #RestController is that you don't have to write #RequestBody and #ResponseBody, that means that any parameter in your controller method which does not have an annotation (like #PathVariable, #ModelAttribute, ...) will implicitly have #RequestBody, and must therefore be POSTed as the HTTP entity body. So you need to send JSON/XML as part of a POST. What you have done is to send data on as part of the URL, which makes it a request parameter and not body-data, and you need #RequestParam to to extract data from the URL.
Also, I would recommend that you use the #GetMapping/#PostMapping or include the method parameter in the #RequestMapping annotation, it is highly unlikely that you want a service to be used for both POST and GET, so you should be as specific as possible in you controller method descriptions, to limit error scenarios.
The reason the second URL does not work is because when using #RequestBody the data you are sending to the endpoint needs to come through via the data attribute in the request header. When you append ?attr=value to your URL that is sending the attribute in the params header.
There are two ways to fix this:
Change your endpoint to read something like this:
public String test2(#RequestParam("value") TestClass req) {
//Endpoint code
}
Change your endpoint to read something like this:
#RequestMapping(value="test2",method=RequestMethod.POST)
public String test2(#RequestBody TestClass req){
//Endpoint code
}
and make your call similar to this (e.g. angularjs):
http.post({url:/*url*/,data:/*object to send*/});
The second option will most likely be what you want to go with because it looks like you are trying to send a json object to your endpoint and I believe you can only do that by making a POST request rather than a GET request
Just leave out the #RequestBody annotation, as this is only for POST requests.
public String test2(#Valid TestClass req) {
return "test2";
}
When you declare a controller method parameter as #RequestBody, you are wishing it to be recovered from the request body and not as a "regular" http parameter.
You could try using any kind of plugin for Firefox (RESTClient) or Chrome (PostMan) and try using one of them. You could do it using SoapUI as well.
The request should be a POST to the requested url this way:
POST http://localhost:8080/test2
You must provide http headers provinding expected Content-Type and Accept. In case of using Json, set them like this:
Content-Type: application/json
Accept: text/html (As your method returns only a String)
And then write the param to the request body. If in Json, like this:
{
"value":"the provided value"
}

How use PUT method in Springboot Restcontroller?

Am developing an application using Spring boot.I tried with all representations verbs like GET, POST , DELETE all are working fine too. By using PUT method, it's not supporting in spring boot. Whether I need to add any new configuration.
Put method works only the request not have any parameters. If i add any query parameter or form data it doesnt work. Kindly any expertize will help me to solve this issue.
#RequestMapping("/student/info")
#RequestMapping(method = RequestMethod.PUT)
public #ResponseBody String updateStudent(#RequestParam(value = "stdName")String stdName){
LOG.info(stdName);
return "ok";
}
Request method 'PUT' not supported
This code will work fine. You must specify request mapping in class level or in function
level.
#RequestMapping(value = "/student/info", method = RequestMethod.PUT)
public #ResponseBody String updateStudent(#RequestBody Student student){
LOG.info(student.toString());
return "ok";
}
Have you tried the following Request Mapping:
#RequestMapping(value = "/student/info", method = RequestMethod.PUT)
There's no need to separate the value and the Request Method for the URI.
Since Spring 4.3 you can use #PutMapping("url") : https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/PutMapping.html
In this case it will be:
#PutMapping("/student/info")
public #ResponseBody String updateStudent(#RequestParam(value = "stdName")String stdName){
LOG.info(stdName);
return "ok";
}
I meet the same issue with spring boot 1.5.*,I fixed it by follow:
#RequestMapping(value = "/nick", method = RequestMethod.PUT)
public Result updateNick(String nick) {
return resultOk();
}
Add this bean
#Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory(){
#Override
protected void customizeConnector(Connector connector) {
super.customizeConnector(connector);
connector.setParseBodyMethods("POST,PUT,DELETE");
}
};
}
see also
https://stackoverflow.com/a/25383378/4639921
https://stackoverflow.com/a/47300174/4639921
you can add #RestController annotation before your class.
#RestController
#RequestMapping(value = "/v1/range")
public class RangeRestController {
}

Categories

Resources