Java springboot POST request giving 404 - spring-boot

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

Spring Webclient Post Method `BadRequest` error for a request that works in Postman (and curl)

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

how to send a single String to a RestAPI endpoint using CURL

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.

HTTP Status - 401 Unauthorized

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.

Parse request parameters without writing wrapper class

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"}
>>>>>>>>>

Unsupported Media Type in jersey RESTfull api

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.

Resources