Troubles posting a JSON value using Spring Boot - java

I am trying to make a post request using json but in postman the request is successful only if I make the request like this: email#example.com. If I make a request using the standard JSON format {"email":"email#example.com"} I get "invalid email id". I should mention that content type application/json header is checked in postman, and I am making the request in body/raw.
I have tried messing with #RequestBody/#RequestParam annotations, using consumes = "application/json" but I am unsuccessful and I couldn't find a similar issue after lots of googling either.
my controller:
#RestController
public class UserController {
#Autowired
private UserService userService;
#PostMapping(value = "/forgot-password", consumes = "application/json")
public String forgotPassword(#RequestBody String email) {
String response = userService.forgotPassword(email);
if (!response.startsWith("Invalid")) {
response = "http://localhost:8080/reset-password?token=" + response;
}
return response;
}
user service:
public String forgotPassword(String email) {
Optional<User> userOptional = Optional
.ofNullable(userRepository.findByEmail(email));
if (!userOptional.isPresent()) {
return "Invalid email id.";
}
User user = userOptional.get();
user.setToken(generateToken());
user.setTokenCreationDate(LocalDateTime.now());
user = userRepository.save(user);
return user.getToken();
}

Simply put, the #RequestBody annotation maps the HttpRequest body to a transfer or domain object.You need to put object instead of String
Your endpoint should be like Below.
#PostMapping(value = "/forgot-password", consumes = "application/json")
public String forgotPassword(#RequestBody EmailDto email) {
String response = userService.forgotPassword(email.getEmail);
// ...
return response;
}
Your DTO should be like below
public class EmailDto {
private String email;
//Getters and Setters
}

You should have Email model with string property email.
public EmailPayload {
String email;
.....
Then it will work (it will fit json you provided).
Ofcouse class name can be different, only thing that must match is email property, then in your Controller your #RequestBody will be this class, and not String you have now.

Related

PUT request with json Body and multipart files array

I have a rest java webservice using a PUT method for updating an employee.
The web service should take a list of files and a json containig the infos to be updated.
The method has the following signature
#RequestMapping(value = "/employees/{employeeId}", method = RequestMethod.PUT, consumes =
MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> updateEmployee(
#RequestPart EmployeeUserUpdateDto employeeDto,
#PathVariable("employeeId") int employeeId,
#RequestPart MultipartFile[] uploadedFiles, BindingResult bindingResult)
When i test this request with postman like follows it says that my json is not present:
PS : I have a similar post request for adding an employee, working just fine with the same configuration , the sole diffrence between the 2 requests is the pathvariable and PUT not POST
add over method : #ResponseBody
You can get multipart request in dto wrapper like this:
#PutMapping("/upload-poc")
ResponseEntity<?> uploadFileWithData(#ModelAttribute TestModel model){
log.info("File Exist: {}",model.getImage().get(0).getOriginalFilename());
log.info("Data: {}", model);
return new ResponseEntity<>(HttpStatus.OK);
}
#Getter
#Setter
#ToString
class TestModel{
private List<MultipartFile> images;
//#NotNull(message = "Name must be provided")
#Size(min = 2, max = 6)
private String name;
private Long id;
}
I am uploading 3 files in one request.
Here is the post man request sample:

Error code 415 when forwarding a POST from an api to another

I'm sending an application/json type from the postman client to a java API that forwards all the requests to the specific API for that case.
On this concrete case, I have a login API and I want to center code heard this JSON:
JSON from the postman
{
"name": "random name",
"password": "random passwd"
}
The API that does the forward
#RequestMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String redirectHttpRequest(HttpServletRequest request, #Value("${endpoint}") String newURL,
HttpServletResponse response) throws IOException {
try {
RestTemplate restTemplate = new RestTemplate();
String result = null;
String body = IOUtils.toString(request.getReader());
if (request.getMethod().equals("GET")) {
// result = restTemplate.getForObject(redirectUrl.toString(), String.class);
} else if (request.getMethod().equals("POST")) {
result = restTemplate.postForObject(newURL, body, String.class);
}
return result;
} catch (HttpClientErrorException e) {
System.out.println(e);
return "OLA";
}
}
That new URL is the URL were the other API is (which, in this case, is localhost:8080 and is from the application.properties file).
I've tested the login API through postman and it works, but when I try to connect it to that forward API I got the following error:
org.springframework.web.client.HttpClientErrorException: 415 null.
I would like to know what I am doing wrong or an alternative way to do it.
Postman call
Second endpoint code
The value of the body passed to the second endpoint
The User class
public class User {
private String name;
private String password;
private List<String> groups;
public User(String name, String password) {
this.name = name;
this.password = password;
this.groups = new ArrayList<String>();
}
public User() {
}
public String getName() {
return this.name;
}
public String getPassword() {
return this.password;
}
public List<String> getGroups() {
return this.groups;
}
public String toString() {
return "User: " + this.name + "\nGroups: " + this.groups;
}
The problem is that you are getting the 415 error code. That means that your /login endpoint is not expecting the payload type you are sending him, see here
415 (Unsupported Media Type)
The 415 error response indicates that the API is not able to process the client’s supplied media type, as indicated by the Content-Type request header. For example, a client request including data formatted as application/xml will receive a 415 response if the API is only willing to process data formatted as application/json.
For example, the client uploads an image as image/svg+xml, but the server requires that images use a different format.
I think is this because when you call postForObject, you are not telling the media type of your payload. So instead of sending the json String alone, you need to wrap it into an HttpEntity that holds the body and also a header that specifies the media type of the payload you are forwarding. Try this out:
...
} else if (request.getMethod().equals("POST")) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
HttpEntity<String> entity = new HttpEntity<>(body, headers);
result = restTemplate.postForObject(newURL, entity, String.class);
}
...

error : The server refused this request because the request entity is in a format not supported by the requested resource for the requested method

I am making a simple API using Spring. and i am getting this error while uploading and mapping file.
The server refused this request because the request entity is in a format not supported by the requested resource for the requested method.
this is my Controller ->
#RequestMapping(value = "/Hi", method = RequestMethod.POST, produces = { "application/json" })
#ResponseBody
public BasicResponse UploadData(#RequestBody CropImageData cropImageData, HttpServletRequest request) {
BasicResponse basicResponse = new BasicResponse();
System.out.println(cropImageData.getCropId());
return basicResponse;
}
My cropImageData model class ->
public class CropImageData {
#JsonProperty("cropImages")
private MultipartFile[] cropImages;
#JsonProperty("cropId")
private String cropId;
public MultipartFile[] getCropImages() {
return cropImages;
}
public void setCropImages(MultipartFile[] cropImages) {
this.cropImages = cropImages;
}
public String getCropId() {
return cropId;
}
public void setCropId(String cropId) {
this.cropId = cropId;
}
}
this is how i am sending request via POSTMAN.
With Postman, you are sending a HTTP post form-data but your end point is not configured to receive this format (the consumes = { "multipart/form-data" } annotation is missing).
Instead of your model class, you should change the signature of your method to something like that:
public BasicResponse UploadData(#RequestPart("cropId") String cropId, #RequestPart("cropImages") MultipartFile file)

Could not read JSON: Unexpected end-of-input in field name

I am developing a Spring MVC web application. I am not still develop the UI. So I am testing my services using Advance Rest Client tool.
My Controller
#Controller
#RequestMapping("/testController")
public class TestController {
#Autowired
private TestService testService;
#RequestMapping(value = "/test", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public
#ResponseBody void testMethod(#RequestBody TestParam testParam) {
String tenant = testParam.getTenantCode();
String testString = tenant + " is the tenant";
}
}
TestParam.java class
public class TestParam {
private String testVar;
private String tenantCode;
public String getTenantCode() {
return tenantCode;
}
public void setTenantCode(String tenantCode) {
this.tenantCode = tenantCode;
}
public String getTestVar() {
return testVar;
}
public void setTestVar(String testVar) {
this.testVar = testVar;
}
}
I send the request using Advance Rest Client and headers and request link has set correctly.
{"testVar":"Test","tenantCode":"DEMO"}
Request link
http://localhost:8080/myApp/controller/testController/test
It works correctly when TestParam has one veriable. When it becomes two or more it gives an Error and it not hit the testMethod.
exception is com.fasterxml.jackson.core.JsonParseException: Unexpected end-of-input in field name at [Source:org.apache.catalina.connector.CoyoteInputStream#7b24d498; line: 1, column: 43]
at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:181)
at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.read(MappingJackson2HttpMessageConverter.java:173)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:135)
I went throw more articles and I still couldn't find the answer.
Increasing Content-Length: in header works
Whats your json format ? I think json format uses literal \n's as delimiters, please be sure that the JSON actions and sources are not pretty printed.
There is an issue in ARC where there is no payload and the response is of a type of json. Parser is throwing error because the string is empty and the response report is crashing.

How do I retrieve query parameters in a Spring Boot controller?

I am developing a project using Spring Boot. I've a controller which accepts GET requests.
Currently I'm accepting requests to the following kind of URLs:
http://localhost:8888/user/data/002
but I want to accept requests using query parameters:
http://localhost:8888/user?data=002
Here's the code of my controller:
#RequestMapping(value="/data/{itemid}", method = RequestMethod.GET)
public #ResponseBody
item getitem(#PathVariable("itemid") String itemid) {
item i = itemDao.findOne(itemid);
String itemname = i.getItemname();
String price = i.getPrice();
return i;
}
Use #RequestParam
#RequestMapping(value="user", method = RequestMethod.GET)
public #ResponseBody Item getItem(#RequestParam("data") String itemid){
Item i = itemDao.findOne(itemid);
String itemName = i.getItemName();
String price = i.getPrice();
return i;
}
While the accepted answer by afraisse is absolutely correct in terms of using #RequestParam, I would further suggest to use an Optional<> as you cannot always ensure the right parameter is used. Also, if you need an Integer or Long just use that data type to avoid casting types later on in the DAO.
#RequestMapping(value="/data", method = RequestMethod.GET)
public #ResponseBody
Item getItem(#RequestParam("itemid") Optional<Integer> itemid) {
if( itemid.isPresent()){
Item i = itemDao.findOne(itemid.get());
return i;
} else ....
}
To accept both #PathVariable and #RequestParam in the same /user endpoint:
#GetMapping(path = {"/user", "/user/{data}"})
public void user(#PathVariable(required=false,name="data") String data,
#RequestParam(required=false) Map<String,String> qparams) {
qparams.forEach((a,b) -> {
System.out.println(String.format("%s -> %s",a,b));
}
if (data != null) {
System.out.println(data);
}
}
Testing with curl:
curl 'http://localhost:8080/user/books'
curl 'http://localhost:8080/user?book=ofdreams&name=nietzsche'
In Spring boot: 2.1.6, you can use like below:
#GetMapping("/orders")
#ApiOperation(value = "retrieve orders", response = OrderResponse.class, responseContainer = "List")
public List<OrderResponse> getOrders(
#RequestParam(value = "creationDateTimeFrom", required = true) String creationDateTimeFrom,
#RequestParam(value = "creationDateTimeTo", required = true) String creationDateTimeTo,
#RequestParam(value = "location_id", required = true) String location_id) {
// TODO...
return response;
#ApiOperation is an annotation that comes from Swagger api, It is used for documenting the apis.
To accept both Path Variable and query Param in the same endpoint:
#RequestMapping(value = "/hello/{name}", method = RequestMethod.POST)
public String sayHi(
#PathVariable("name") String name,
#RequestBody Topic topic,
//#RequestParam(required = false, name = "s") String s,
#RequestParam Map<String, String> req) {
return "Hi "+name +" Topic : "+ topic+" RequestParams : "+req;
}
URL looks like : http://localhost:8080/hello/testUser?city=Pune&Pin=411058&state=Maha
I was interested in this as well and came across some examples on the Spring Boot site.
// get with query string parameters e.g. /system/resource?id="rtze1cd2"&person="sam smith"
// so below the first query parameter id is the variable and name is the variable
// id is shown below as a RequestParam
#GetMapping("/system/resource")
// this is for swagger docs
#ApiOperation(value = "Get the resource identified by id and person")
ResponseEntity<?> getSomeResourceWithParameters(#RequestParam String id, #RequestParam("person") String name) {
InterestingResource resource = getMyInterestingResourc(id, name);
logger.info("Request to get an id of "+id+" with a name of person: "+name);
return new ResponseEntity<Object>(resource, HttpStatus.OK);
}
See here also

Categories