Spring boot : REST API behaviour inconsistent post version upgrade - spring-boot

I have issue after upgrading to Spring Boot 2.3.0.RELEASE from 1.5.10.RELEASE. Our controller API looks like -
#RequestMapping(value = "/card", method = RequestMethod.GET)
public CardRespDTO getCards(#RequestParam String profileId, #RequestParam(required = false) String banner, #RequestParam(required = false) String paymentGatewayVersion);
Consumer were able to call this API by not passing profileId param but by just providing some USER_ID header. But post the version upgrade, those calls are failing with below error -
org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'profileId' is not present
Can someone please help identifying the issue here? We can't ask consumer to make a change.

Marking profileId as not required should do the trick:
#RequestMapping(value = "/card", method = RequestMethod.GET)
public CardRespDTO getCards(#RequestParam(required = false) String profileId,
#RequestParam(required = false) String banner,
#RequestParam(required = false) String paymentGatewayVersion)

Related

Avoid duplicate code in Controllers and service

I am using Spring framework.
I wrote some pretty long code to save some results.
So later it turned out in other controllers I will also need this code. Just with small differences for example returning some other strings.
So of course every controller will have its own mapping. So the parameters will be duplicate anyway.
But now for the code inside the mapping method.
I was thinking putting the code in the service of the original controller. Then the other controllers will call this service. The service of course will have plenty of parameters + the slight differences between the controllers. Or should I make like a general service, have good documentation there because of course the methods there will be general and later I should know what they were for.
#PostMapping("/testcase") public RedirectView saveResult(Model model, #ModelAttribute("testResultEntity") TestResultEntity testResultEntity, RedirectAttributes redirectAttributes , #RequestParam(required = false) String version , #RequestParam(required = false,defaultValue = "0") String page, #RequestParam(required = false) String operation, Authentication authentication,Locale locale)
{ // here comes long code, which will be used also in other controllers ;
}
If all the controller mappings have the same signature you can create a parent class with the common implementation.
Something like this:
public abstract class BaseAbstractController {
// specific logic per controller
abstract String specific();
public RedirectView save(Model model, #ModelAttribute("testResultEntity") TestResultEntity testResultEntity,
RedirectAttributes redirectAttributes, #RequestParam(required = false) String version,
#RequestParam(required = false, defaultValue = "0") String page, #RequestParam(required = false) String operation,
Authentication authentication, Locale locale) {
// here comes long code, which will be used also in other controllers ;
String specific = specific();
}
}
#Controller
public class TestController extends BaseAbstractController {
#Override
String specific() {
return "something"; // here goes your specific logic;
}
#PostMapping("/testcase")
public RedirectView saveResult(Model model, #ModelAttribute("testResultEntity") TestResultEntity testResultEntity,
RedirectAttributes redirectAttributes, #RequestParam(required = false) String version,
#RequestParam(required = false, defaultValue = "0") String page, #RequestParam(required = false) String operation,
Authentication authentication, Locale locale) {
return save(model, testResultEntity, redirectAttributes, version, page, operation, authentication, locale);
}
}

Why can #requestparam get file upload data in SpringMVC?

#requestparam functions like request.getquerystring (). Why does she receive a multipart/form-data type contentType when #requestbody cannot?Please tell me why?
#PostMapping(value = "/uploadFileByUserTrainId", consumes = "multipart/form-data")
#Student({Student.Authority.A, Student.Authority.B, Student.Authority.C})
public WebMessage uploadFileByUserTrainId(
#RequestParam(value = "document", required = false) MultipartFile multipartFile,
#RequestParam(value = "documetnRe", required = false) MultipartFile multipartFileRe,
#RequestParam("id") long id,
#RequestParam(value = "documentFileType", required = false) String fileType,
#RequestParam(value = "documentFileReType", required = false) String fileReType,
HttpServletRequest httpServletRequest) {
// todo
}
It is nothing wrong using #RequestParam with Multipart file.
#RequestParam annotation can also be used to associate the part of a "multipart/form-data" request with a method argument supporting the same method argument types. The main difference is that when the method argument is not a String, #RequestParam relies on type conversion via a registered Converter or PropertyEditor

How can I validate the value of #RequestQuery

I am trying to validate the value of the query param below after the equals sign in the REST URI, does anyone know how to do it with Spring 4.1 please?
I want to validate in the method parameters that 'drive' is the passed param but all I can validate is the operation part
I would like to do something like #RequestParam(value = "drive")
localhost/test?operation=drive
#RequestMapping(value = "/test", method = RequestMethod.PUT)
public ResponseEntity<Void> operation(#RequestParam(value = "operation", required = true) String operation)
`
You could use Bean Validation annotations.
If you want to check if the value is allowed, you can use #Pattern with a regular expression:
#Pattern(regexp = "value1|value2|value3", flags = Pattern.Flag.CASE_INSENSITIVE)
#RequestMapping(value = "/test", method = RequestMethod.PUT)
public ResponseEntity<Void> operation(
#RequestParam(value = "operation", required = true)
#Pattern(regexp = "value1|value2|value3", flags = Pattern.Flag.CASE_INSENSITIVE)
String operation) {
...
}

Multipartfile parameter order precedence causing error

Basically, I am sending two parameters , one a String and the other a file to my controller in Spring Boot . In the action, when I receive the file first and then the String next, like so
#RequestMapping(value = "/updatemedia", method = RequestMethod.PATCH,consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> updateMedia(#RequestParam(value ="file") MultipartFile fileToUpload , #RequestParam(value = "keyId") String keyId )
everything is fine and I am able to access the String and the file correctly.
But when I change the order of the parameters , like so
#RequestMapping(value = "/updatemedia", method = RequestMethod.PATCH,consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> updateMedia( #RequestParam(value = "keyId") String keyId , #RequestParam(value ="file") MultipartFile fileToUpload )
and send the params through Postman, I am hitting the below error
I researched a lot but am not able to understand this behaviour.
Because you send keyId in body while it's declared as #RequestParam
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestParam.html .
#RequestParam has nothing to deal with request body, it's passed in request url.
What about your example, the first approach works, because your method expects one #RequestPart, the others are ignored.

Invoking service with #RequestParam and #RequestBody using postman client

Was trying to invoke the service
http://IP:8080/PQRS/LMN/XYZ/runTest/scheduledautomation/1/XYZ
with below JSON String
[ {"paramName":"TEST_TARGET_IDENTIFIER","paramValue":"ETest"},{"paramName":"TEST_SOURCE_ENTRY_IDENTIFIER","paramValue":"com.pack.etest"}]
#ResponseStatus(value = HttpStatus.NO_CONTENT)
#RequestMapping(value = "/runTest/scheduledautomation/{runId}/{testEngine}", method = RequestMethod.POST)
public void runScheduledAutomatedTest(#RequestParam String cronExpresssion,
#RequestParam(required = false) #DateTimeFormat(iso = ISO.DATE_TIME) LocalDateTime endTime,
#PathVariable Integer runId,
#PathVariable TestEngine testEngine,
#RequestBody List<TestEngineParam> testEngineParams) throws Exception { //Some Code }
Response :
Required String parameter 'cronExpresssion' is not present
how to invoke mixed #RequestParam and #RequestBody services on postman client ?
I fear you want a little bit too much: RequestParam, RequestBody AND the whole thing as a REST query. At least two of the three things are mutually exclusive.
I think you could even get Postmaster to do this by modifying the called URL to:
http://IP:8080/PQRS/LMN/XYZ/runTest/scheduledautomation/1/XYZ?cronExpression=your-expression
Of course this would ruin your REST interface, but as I said: your handler method is a little bit "over-ambitious".

Resources