Invoking service with #RequestParam and #RequestBody using postman client - spring

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

Related

Spring boot : REST API behaviour inconsistent post version upgrade

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)

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

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.

Change #RequestBody object based on #PathVariable

Below is my application code
#RequestMapping(value = "app/{version}/register", method = RequestMethod.POST, consumes = "application/json")
#ResponseBody
public RegisterMemberResponse registerMember(#Valid #RequestBody RegisterMemberRequest request,#PathVariable Integer version){
return registerservice.register(request);
}
for app version 1 my RegisterMemberRequest class is
public class RegisterMemberRequest{
#NotNull
private String firstName;
#NotNull
private String lastName;
//gatter & setter...
}
and for app version 2 my request class is
public class LatestRegisterMemberRequest extends RegisterMemberRequest{
#NotNull
private String middleName;
//getter & setter...
}
so how i can i change my registerMember() method in such a way that i can serve both version 1 & 2 request uri.
If you want to hardcode the version number into the url (which I would not recommend), you could easily use two different controller methods with hardcoded paths like app/v1/register and app/v2/register.
Another way would be to use content negotiation and route the requests according to a given content-type, e.g. application/vnd+<YOURCOMPANY>.<DATATYPE_AND_VERSION>+json, also using separate rest controller methods annotated with #Consumes.
I think you can make use of Requestmapping-uri-templates-regex , version number will be the #PathVariable write your business logic to decide what should be the response body depends on pathvariable version.

Resources