Webhook to collect a JSON: Request method POST not supported - java

I'm writing a controller with Java for a webhook URL that receives a POST method call, with a JSON body, that I need to collect.
This is a simplified version of the controller, with Spring annotations:
#RestController
public class MyWebhoook {
#PostMapping("/my-webhook")
public void getMyJson(#RequestBody Map<String, Object> json) {
System.out.println("WebHook collected JSON: " + json);
}
}
I test it with Postman sending this JSON:
Header: Content-Type / application/json
{
"webhookKey" : "tranviaVermellCostaAvall",
"token" : "xx",
"channelId": 1,
"propertyId": "999999",
"status": "new",
"reservationId": "111211221",
"reservationStatus" : 1
}
And I get this answer:
{
"timestamp": "2019-04-09T07:23:38.093+0000",
"status": 405,
"error": "Method Not Allowed",
"message": "Request method 'POST' not supported",
"path": "/my-webhook"
}
The server log, gives some more information:
Request method 'POST' not supported, path=/my-webhook}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#7756c3cd
I've tried those different approaches, with the same result:
#RequestMapping(value = "/my-webhook", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST) instead of the #PostMapping("/my-webhook") annotation.
Modelling the received JSON as a java object instead of the Map<String, Object> json.
Using HttpServletRequest instead of the #RequestBody annotation, trying to read the request as a String.
I do not understand the reason why the POST method is not allowed. Any help, would be very much appreciated.

I added {} between your method and got a 200 as return. I added the pictures below on what code, request and console output i got.

I copied your code to my spring boot app, worked perfectly via postman...
API:
#PostMapping("/my-webhook")
public void getMyJson(#RequestBody Map<String, Object> json) {
System.out.println("WebHook collected JSON: " + json);
}
RequestBody:
{
"webhookKey" : "tranviaVermellCostaAvall",
"token" : "xx",
"channelId": 1,
"propertyId": "999999",
"status": "new",
"reservationId": "111211221",
"reservationStatus" : 1
}
URL: http://localhost:8080/my-webhook
Try to:
Update and Clean your project.
Invalidate IDE cache and restart it, and try again.

The problem was with the CSRF (Cross-site request forgery) security configuration. The path of the webhook, has to be taken out of the CSRF control. Otherwise, the POST request doesn't pass the CSRF control.
This is a simplified extract of the security settings:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http)throws Exception{
http
.csrf()
.ignoringAntMatchers("/my/webhook")

Related

My microservice is not receiving "Authorization" from request header when i use feign-reactive to call it from another microservice

I have 2 microservices, ProductStore and InvoiceStore.
I want ProductStore to provide product information through an API and InvoiceStore to call that API to get product information from ProductStore.
But ProductStore needs Authorization information to check user authentication so I use #RequestHeader("Authorization") String auth as argument variable in my FeignAPI to send it to ProductStore.
But it reported that he did not receive the Authorization data when i test it.
I use #RequestHeader like that because I see it in the examples of feign-reactive all feature
I don't know if I did something wrong somewhere or I misunderstood the usage of #RequestHeader.
Help me please! Here is my code.
My ProductStore provides API to be able to get product information.
#GetMapping("products")
public ResponseEntity<String> test(#RequestHeader("Authorization") String authorization) {
log.debug("Authorization is {}", authorization);
return ResponseEntity.ok().body("all products");
}
And my InvoiceStore call that API with feign-reactive WebReactiveFeign.
I followed the instructions in the readme of Playtika feign-reactive and applied it to my project as follows
First, I write FeignAPI
#Headers({ "Accept: application/json" })
public interface FeignClientAPI {
#RequestLine("GET /products")
Mono<String> getProducts(#RequestHeader("Authorization") String authorization);
}
And then, I build the client in IvoiceService
#Service
#Transactional
public class InvoiceService {
private final FeignClientAPI client = WebReactiveFeign.<FeignClientAPI>builder().target(FeignClientAPI.class, "http://localhost:8082");
public Mono<String> testFeign(String authorization){
log.debug("Call api with authorization: {}", authorization);
return client.getTest(authorization);
}
}
And then, I create an API
#GetMapping("/invoice/test")
public Mono<ResponseEntity<String>> getProducts(#RequestHeader("Authorization") String authorization) {
return invoiceService.testFeign(authorization)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)))
.map(response -> ResponseEntity.ok().body(response));
}
Finally, I shoot an GET request to localhost:8083/invoice/test and I got an error
{
"title": "Internal Server Error",
"status": 500,
"detail": "[400 Bad Request] during [GET] to [http://localhost:8082/products] [FeignClientAPI#getTest(String)]: [{\n \"title\" : \"Bad Request\",\n \"status\" : 400,\n \"detail\" : \"Required request header 'Authorization' for method parameter type String is not present\",\n \"path\" : \"/products\",\n \"message\" : \"error.http.400\"\n}]",
"path": "/invoice/test",
"message": "error.http.500"
}
Tell me where i did wrong, Please!!!
Thank you for everything.
your code is totally wrong and i think you should get compile time error because testFeign(String authorization) need a string input but when you call it ( invoiceService.testFeign().switchIfEmpty ... ) you are not passing any input to it.
i should check the main code ,but i think you are passing null value as authorization in client side ( probably ).
I found the solution to this problem.
I misinterpreted how to use reactive feign before, which resulted in it not working.
I've added #EnableReactiveFeignClients and #EnableFeignClients for my spring boot app
#EnableReactiveFeignClients
#EnableFeignClients
public class AnswerStoreApp {
// main method
}
and then, I create an interface with #ReactiveFeignClient(name = "my-other-service")
#ReactiveFeignClient(name = "my-other-service")
public interface FeignClientService {
#GetMapping("/api/questions/test-feign")
Mono<String> demo(#RequestHeader("Authorization") String authorize);
// More request
}
finally, I can use FeignClientService to get the data that I need
#Autowired
private FeignClientService feignClientService;
// Some method
#GetMapping("/invoice/test")
public Mono<ResponseEntity<String>> getProducts(#RequestHeader("Authorization") String authorization) {
return feignClientService.testFeign(authorization)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)))
.map(response -> ResponseEntity.ok().body(response));
}

IBM MobileFirst Adapter accepting Multipart request

I am a newbie to IBM MobileFirst, I am trying to upload an image using Multipart. Whenever I try to call the API to upload image I get an error in the Postman saying 415 content not found or 500 server error. So I just wanted to know does IBM mobile first java adapter accepts multi-part requests?
I have attached the Java code used , but none of these are working:
1)
#RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
public #ResponseBody
String uploadFileHandler(#RequestParam("file") MultipartFile file)
{
return null;
}
tried this also :
#POST
#Path("/upload")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#OAuthSecurity(enabled=false)
public ResponseEntity<?> upload(#RequestParam("files") MultipartFile files) {
log.info("XXXXXXXXXXXXXXXXXXXX");
return null;
}
#POST
#Path("/addEmployeeAttachment")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.MULTIPART_FORM_DATA)
#OAuthSecurity(enabled=false)
public #ResponseBody Map<String, Object> addEmployeeAttachment(
#RequestParam(required = false, value = "attachmentFile") MultipartFile attachmentFile) {
log.info("xxxxxxxxxx");
return null;
}
With reference to IBM Mobile first development reference document https://www.ibm.com/support/knowledgecenter/SSHS8R_8.0.0/com.ibm.worklight.apiref.doc/apiref/c_restapi_oview.html
We can use Deploy (POST) for Deploys a multipart compressed file.
JSON example:-
{
"ok" : false,
"productVersion" : "8.0",
"transaction" : {
"appServerId" : "Tomcat",
"description" : {
"name" : "myname",
"type" : "mytype",
},
"errors" : [
{
"details" : "An internal error occured.",
},
...
],
"id" : 1,
"project" : {
"name" : "myproject",
},
"status" : "FAILURE",
"timeCreated" : "2014-04-13T00:18:36.979Z",
"timeUpdated" : "2014-04-14T00:18:36.979Z",
"type" : "UPLOAD_ARTIFACT",
"userName" : "demouser",
},
}
Standard Error code:-
Errors 400 No deployable data is provided. 403 The user is not
authorized to call this service. 404 The corresponding runtime is not
found or not running. 500 An internal error occurred.
Could you pleas refer How can I make a multipart/form-data POST request using Java? as well.
I hope it will help you to understand more about multipart API.

Mapping incoming JSON to a class in spring boot

I'm struggling to understand why I'm getting the following error when I call my spring boot end point
{
"timestamp": 1489573322678,
"status": 406,
"error": "Not Acceptable",
"exception": "org.springframework.web.HttpMediaTypeNotAcceptableException",
"message": "Could not find acceptable representation",
"path": "/quotes"
}
This is the request that I'm sending to the server
POST /quotes HTTP/1.1
Host: localhost:8080
tamid: 5
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 94370a3f-6165-106f-f27f-44a44093e0d5
{
"test": "works"
}
I would like the incoming JSON request body to map to a java class I have defined. Here is the class.
#Embedded
public class QuoteVersion {
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
public void validate() {
}
}
I'm using the #Embedded annotation for use with a mongodb mapping library that I'm hoping is unrelated to the issue I'm facing
Here is the controller method
#RequestMapping(
path = "/quotes",
method = RequestMethod.POST,
headers = "Accept=application/json",
produces = "application/json"
)
public #ResponseBody QuoteStatus create (#RequestHeader(value = "tamid") String tamId,
#RequestBody QuoteVersion firstQuoteVersion) {
// final QuoteVersion firstQuoteVersion = this.quoteFactory.createQuoteVersion(incomingQuote);
final User currentUser = User.getFromTamId(tamId);
currentUser.can(Permissions.CREATE_QUOTE);
firstQuoteVersion.validate();
final Quote newQuote = new Quote();
newQuote.addVersion(firstQuoteVersion);
this.dataRepository.save(newQuote);
QuoteStatus qs = new QuoteStatus(newQuote);
return qs;
}
I'm guessing that Spring Boot for some reason does not understand how to map the incoming payload to the class I have defined but I have no idea how to fix the issue. Thanks in advance for any help you may have to offer.
Spring clearly indicates this problem:
HttpMediaTypeNotAcceptableException
This means that in your content-type header you provided the wrong information or made a syntactical mistake. Try putting there something like application/json.
Also
Make sure the other end will accept it. You currently only accepting requests with an accept header with value application/json. I don't think that is what you want.
So either remove that requirement or add this header to the request.

Spring Rest Service Post request error

It may be a basic question related to Spring Rest service Post request
Below is my Controller mapping code:
#RequestMapping(value = "test", method = RequestMethod.POST)
#ResponseBody
public String addFruits(#RequestBody RequestWrapper fruits) {
// ...
System.out.println("test");
return null;
}
Below is the RequestWrapper class:
public class RequestWrapper{
List<String> ids;
String languageCode;
...
}
Now if in advanced Chrome rest client, with content-type as application/json
if I post the following request :
["ids": [{ "1","2","3","4"}]
,
"languageCode" : "en_US"
]
I get the following error:
Error 400: SRVE0295E: Error reported: 400
Any clue as to where I am going wrong?
The issue was due to an incorrect JSON format in the actual question.
With due help from Soitirios Delimanolis and Alejandro Agapito Bautista could correct the json format and the code worked.
The correct json format is:
{ "ids": [ 1, 2, 3, 4 ], "languageCode": "en_US" }
Also learnt from Alejandro Agapito Bautista's the json validation link
jsonlint.com

Deserializing json array in Spring MVC controller

I am sending a list of json object and trying to deserialize it in my Spring controller. But all the time I am getting error of 'Bad request' and results into a status code of 415. However, my json array is a valid one.
json is -
{
"users": [
{
"userName": "john",
"email": "john#gmail.com",
"user_id": "u223344"
},
{
"userName": "Smith",
"email": "smith#gmail.com",
"user_id": "u223345"
}
]
}
Ajax call is as follows -
$.ajax({
url: $("#addNewUser").attr("action"),
data: JSON.stringify({users : dataToSend}),
dataType: 'json',
type: "POST",
beforeSend: function(xhr) {
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
},
success: function(data){
alert('success= ' + data);
},
error:function(data,status,er) {
alert("error: "+ data.responseText +" status: "+status+" er:"+er);
}
});
Wrapper classes are as follows. User and UserWrapper class -
public class User {
private String email;
private String userName;
private String user_id;
//getters and setters
}
public class UserWrapper {
private List<User> userList;
//getter and setter
}
And finally the spring MVC controller is -
#RequestMapping(value="/user/add", method=RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public void createTeamMember(#RequestBody UserWrapper userWrapper) {
try{
for(User user : userWrapper.getUserList()){
System.out.println(user.getEmail());
}
}catch(Exception ex){
ex.printStackTrace();
}
}
I've added dependency for jackson-core and jackson-mapper in pom.xml. And I am using Spring 4.0.3. Any help is appreciated.
As #shazin is saying, you've most likely posted a wrong method to your question, or if not, simply make a change that he suggested.
You'll need another fix, and that is renaming the usersList property from UserWrapper to users so that it matches the JSON property being sent.
We these fixes, you should not have further problems, since your request is OK.
I think you need to change your #RequestBody POJO to UserWrapper
#RequestMapping(value="/task/add", method=RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public void createTeamMember(#RequestBody UserWrapper userWrapper) {
// Code to create members
}
I will not suspect server side binding error yet because you are getting 415 - Unsupported Media Type error. You are setting correct media type on controller and hence server side is looking good.
At client side, Please make sure you are using jquery 1.5+ to make sure beforeSend() method is getting invoked.
Easier way to content type will be,
$.ajax({
url:api,
....
contentType: "application/json"
});
Please inspect network request from browser and make sure content type is set in header.
If you receive 400-Bad Request, then you can start looking deserializing issues.

Categories