I am trying a POST request in POSTMAN but even though its reaching the tomcat server node, I get following error in my localhost_access.log file
"POST /app/MyService/myControllerMethod HTTP/1.1" 404 1010
My Controller class is something like this :
#Controller("myServicecontroller")
#RequestMapping({"/MyService"})
public class MyServiceController {
#RequestMapping(value = {"myControllerMethod"}, method = {RequestMethod.POST})
public String myControllerMethodBackgroundCallBack(HttpServletRequest httpReq,
#RequestBody String request) {
// rest piece of code
}
}
Now my postman curl I am trying with empty data (tried with some value also) but get above 404 error response
curl --location --request POST 'http://my-ip-address:8080/app/MyService/myControllerMethod' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'My-Header-One: lskdnansdlknalkasndl' \
--header 'My-Header-Two: sadasdsa' \
--data-raw '{}'
What am I doing wrong? (app in above url is my service which works fine in other requests)
Same thing when I try with following code it is able to hit the api 200
HttpClient httpClient = new HttpClient();
PostMethod postMethod = new PostMethod(url);
postMethod.setRequestBody(requestString);
httpClient.setConnectionTimeout(httpReadTimeOut);
httpClient.executeMethod(postMethod);
I have successfully replicated this issue and found the root cause.
Root Cause
#ResponseBody annotation is missing in myControllerMethodBackgroundCallBack method.
Fix
#RequestMapping(value = {"myControllerMethod"}, method = {RequestMethod.POST})
#ResponseBody
public String myControllerMethodBackgroundCallBack(HttpServletRequest httpReq,
#RequestBody String request) {
// rest piece of code
}
}
Why?
#ResponseBody annotation is required with #Controller annotation and if use #RestController annotation then #ResponseBody annotation is not required.
In Short-
#RestController = #Controller + #ResponseBody
You can read more about #Controller and #RestController here https://medium.com/#akshaypawar911/java-spring-framework-controller-vs-restcontroller-3ef2eb360917
Related
I'm calling an external API via WebClient to create a resource. But getting WebClientResponseException$BadRequest while testing from Postman. Here are few things I've tried without success:
Building URI path from uribuilder
Coverting entity to MultiValueMap before inserting into the request
Controller:
#PostMapping("/createMessage")
public String createMessage(#RequestBody Message request) {
return service.createMessage(request);
}
Service:
public String createMessage(Message requestBody) {
ObjectMapper mapper = new ObjectMapper();
MultiValueMap requestBodyForm = new LinkedMultiValueMap<String, Object>();
Map<String, Object> requestBodyMap = mapper.convertValue(requestBody, new TypeReference<Map<String, Object>>() {});
requestBodyForm.setAll(requestBodyMap);
String id = webClient.post()
.uri(properties.getMessageUrl())
.contentType(MediaType.APPLICATION_JSON)
.headers( headers ->
headers.setBasicAuth(user,pass))
.body(BodyInserters.fromValue(requestBodyForm))
.retrieve()
.bodyToMono(String.class)
.block();
return id;
}
Any direction where might be the problem would help a lot.
The external service is an IoT device controller API, with predefined message format:
$ curl --location --request POST 'http://external-service/message' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic xxxxxxxxxxxx' \
--data-raw '[{
"message": "Testing service reachability",
"defaulttext": "This is Message Zone",
"startDate": "2021-05-25 15:20:00",
"duration":10,
...
}]'
198
I have a #RestController with an endpoint that receives a single String :
#RestController
public class ScriptController {
private Logger logger = LoggerFactory.getLogger(ScriptController.class);
public ScriptController(Engine engine) {
this.engine = engine;
}
#RequestMapping(value = "/run", method = RequestMethod.POST)
public Object run(#RequestBody String script){
return engine.run(script);
}
}
when I send a request to this endpoint using CURL :
curl --request POST localhost:9999/run --data-binary "testObj.hi()"
I am not receiving the exact String ("testObj.hi()") in the Controller, instead I receive the following one :
testObj.hi%28%29=
what is the problem?
when I change the method from POST to GET (in both sides) it works! but I want to use POST method.
By default, the request body is URL encoded in HTTP requests, and since there is no content-type header, spring boot doesn't decode the encoded characters.
Specifying Content-Type header will solve the problem, something like this:
curl --request POST localhost:8080/run --data-binary "testObj.hi()" -H 'Content-Type: text/utf-8'
It works in case of GET requests because parameters are expected to be URL encoded in case of GET request and they are decoded by the spring.
I'm trying to convert from curl to java code with intention to call an API to create a token but I get a 401 response.
Curl code:
curl -X POST \
https://apigw.dev/commercial/oauth/create-token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'client_id=dfdfdfdfd&client_secret=dfdfdf&grant_type=client_credentials'
And here my java code:
#RestController
public class TokenController {
#RequestMapping(value = "/getAccessToken", method = RequestMethod.POST)
public ClientCredentialsResourceDetails getAccessToken(ClientCredentialsResourceDetails resource) throws Exception {
resource.setAccessTokenUri(tokenUri);
resource.setClientId(clientId);
resource.setClientSecret(clientSecret);
resource.setGrantType("client_credentials");
resource.setClientAuthenticationScheme(AuthenticationScheme.header);
resource.setScope(Arrays.asList("read", "write"));
System.out.println(resource);
return resource;
}
}
and here the results:
"timestamp": "2020-04-28T14:02:28.381+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/getAccessToken"
}
I really appreciate your suggestion, Thanks in advance.
You're making a POST request with CURL, but your rest controller is configured as GET. I guess you have another endpoint to /getAccessToken with POST method wich requires the token.
Also, by default, every mehod in a #RestController class will consume an application/json and produce an application/json.
If your request is a Content-Type: application/x-www-form-urlencoded, change the consume type of your request to MediaType.APPLICATION_FORM_URLENCODED_VALUE.
How to handle json requests and parse the request parameters in dropWizard?
#POST
#Path("/test")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String test(#Context final HttpServletRequest request) {
JSONObject data=new JSONObject();
System.out.println(request);
System.out.println(request.getParameterMap());
System.out.println(">>>>>>>>>");
return "{\"status\":\"ok\"}";
}
I wrote the above code and tried the following request.
curl -XPOST -H "Content-Type: application/json" --data {"field1":"val1", "field2":"val2"} http://localhost:8080/test
But request.getParameterMap() is {}
How to parse the parameters without writing a wrapper class?
Your curl command may need some additional quotes around the data (I'm getting an error without them):
curl -H "Content-type: application/json" -X POST -d '{"field1":"tal1", "field2":"val2"}' http://localhost:8080/test
You are sending a POST request without URL parameters. I'm not sure why you are expecting to see something there.
I don't know which version of dropwizard you are using but I couldn't make the combination of #POST and #Path("/something") annotation to behave when a method is annotated. I'm getting HTTP ERROR 404.
To make it work I have to move the #Path annotation to the resource/class level and leave only the #Post annotation at the method.
#Path("/test")
public class SimpleResource {
#POST
#Consumes(MediaType.APPLICATION_JSON)
public String test(final String data) throws IOException {
System.out.println("And now the request body:");
System.out.println(data);
System.out.println(">>>>>>>>>");
return "{\"status\":\"ok\"}";
}
}
To get the body of the request as String just do as above. Taken from here: How to get full REST request body using Jersey?
The console looks like:
INFO [2016-11-24 15:26:29,290] org.eclipse.jetty.server.Server: Started #3539ms
And now the request body:
{"field1":"tal1", "field2":"val2"}
>>>>>>>>>
I am trying to build a RESTfull API using the Jersey library but it gives me an exception.
Here is my Docs class
#XmlRootElement
#XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
public class Docs {
#XmlElement(name = "field")
public String field;
#XmlValue
public String content;
}
#Path("/update")
public class Update {
#POST
#Path("/xml")
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public String createIndexXML(Docs docs)
throws Exception {
System.out.println(docs.content);
return "It works";
}
}
If I try to check it using CURL it throws Error 415 Unsupported Media Type
curl -XPOST "http://localhost:8089/update/xml" -d '<docs>
<field>title</field>
</docs>'
You need to add the content type to your request header. Add -H "Content-Type: application/xml" to yourcurl` call.
I think you're also going to find that there are problems with your annotations on your bean - but that's another issue...
This should work:
curl -H "Content-Type: application/xml"
-X POST -d "<docs><field>title</field></docs>" "http://localhost:8089/update/xml"
You should also try Accept: application/xml; watch out for defining both #Produces and #Consumes! See Using #Consumes and #Produces to Customize Requests and Responses.