RestController Setting default Header for GetMapping - spring

Good Morning,
I have a RestController controller where I have a GetMapping using a header.
If that header does not come with any value, I want to route to a default method, ¿is there any way?
¿Is there any way to set the value of a default header when the rest Client dont send it?
#RestController
#RequestMapping("/api/demo")
#Log4j2
public class RestDemoController{
#GetMapping( value = "/version", headers = "x-api-version=v.1.0")
public String getHeaderValue(#RequestHeader(value=ApiVersionConstans.API_VERSION_HEADER_CODE) String version) {
log.debug("Returning version header");
return ApiVersionConstans.API_VERSION_HEADER_CODE;
}
#GetMapping(value = "/version", headers = "x-api-version=v.1.0_default")
public String getAnoherHeader(#RequestHeader(value=ApiVersionConstans.API_VERSION_HEADER_CODE) String version) {
log.debug("Looking for exisiting tokens");
return "This is another header";
}
}
Regards

Please try this:
#GetMapping("/version")
public String getDefaultHeader(#RequestHeader(value=ApiVersionConstans.API_VERSION_HEADER_CODE, defaultValue="your default value") String version) {
// ...
return "This is default header";
}
When you set #RequestHeader#defaultValue, the header is not required and its value is set to version when the header is missing.
I think javadoc of #RequestHeader is helpful for you:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestHeader.html#required--

Related

Controller Parameter giving a strange error

I have a wrote a project using spring boot my controller were just working fine until I have added
'params' to getmapping annotation
my PlaneTypeVersionedApi Interface down below;
#Validated
#RequestMapping("/version")
public interface PlaneTypeVersionedApi {
#GetMapping(value = "/plane", params = "v1")
ResponseEntity<String> getOnePlaneByProduce1(#RequestParam("plane-type")String planeType);
}
my PlaneTypeVersionedApiImpl Class down below;
#RestController
public class PlaneTypeVersionedApiImpl implements PlaneTypeVersionedApi {
private final PlaneCallerService planeCallerService;
public PlaneTypeVersionedApiImpl (PlaneCallerService planeCallerService) {
this.planeCallerService = planeCallerService;
}
#Override
public ResponseEntity<String> getOnePlaneByProduce1(String planeType) {
return ResponseEntity.ok(planeCallerService.getPlaneType(planeType));
}
}
when I try on Postman for my controller;
localhost:9080/version/plane?plane-type=light-weight?v1
I have 400 bad request and saying
Resolved [org.springframework.web.bind.UnsatisfiedServletRequestParameterException: Parameter conditions "v1" not met for actual request parameters: plane-type={light-weight?v1}]
The syntax of the query parameters on the url is not valid.
Here is the correct syntax : localhost:9080/version/plane?plane-type=light-weight&v1.
https://launchschool.com/books/http/read/what_is_a_url#querystringsparameters
your url is bad not sure what your intent use of params
example 1 valid url = localhost:9080/version/plane?plane-type=light-weight&v1=
using #RequestParam("plane-type") String plane-type
#RequestParam("v1") String v1 is enough to get the value no need use of attribute params
example 2 if you want to use params
#GetMapping(value = "/plane", params = {"v1"}) this mean you want v1 value
ResponseEntity<String> getOnePlaneByProduce1(#RequestParam("v1")String v1);
example 3 you want both
#GetMapping(value = "/plane", params = {"v1","plane-type"}) this mean you want v1 value and plane-type
ResponseEntity<String> getOnePlaneByProduce1(#RequestParam("v1")String v1, #RequestParam("plane-type") String plane-type);
params option just mean that endpoint require to have those params if one you specific is not there it gonna complain

How to write appropriate endpoint in Spring Boot for GET request?

I have an assignment to write simple GET request.
The format that is going to be typed in URL is like this:
http://localhost:8080/api/tasks/20-08-2020
Server should return TODOs for that date. I did managed to write a finder method. But not sure how to write an endpoint. This is what I have so far:
#GetMapping(value = "/{date}", consumes="application/json")
public ResponseEntity<List<Task>> getTasksByDateUsingURL(#PathVariable("date") #DateTimeFormat(pattern="dd-MM-yyyy") #Valid LocalDate dueDate){
List<Task> tasks = taskService.getAllTasksByDate(dueDate);
return new ResponseEntity<List<Task>>(tasks,HttpStatus.OK);
}
This is inside RestController class:
#RestController
#RequestMapping(value="/api/tasks")
public class TaskController {...}
I cannot hit this GET endpoint...
Workaround for your problem is to get the string as parameter and parse it manually
#GetMapping(value = "/{date}", consumes="application/json")
public ResponseEntity<List<Task>> getTasksByDateUsingURL(
#PathVariable("date")
String date
){
LocalDate dueDate = parse(date);
List<Task> tasks = taskService.getAllTasksByDate(dueDate);
return new ResponseEntity<List<Task>>(tasks,HttpStatus.OK);
}
private LocalDate parse(String stringDate) {
// TODO
}
As author said in comments:
When try to call the endpoint from browser, the mapping is not executed.
Seems like that the browser is sending request with wrong Content-Type header. Your mapping is explicitly requires only application/json value.
When try to call the endpoint from Postman, the application returns 400 status.
I could not see the body of response, but I guess the problem is #Valid annotation on the parameter. How should Spring validate the LocalDate?
So the solution is to remove consumes="application/json" from mapping or send corresponding Content-Type value
and remove #Valid annotation from parameter.

Spring Custom Annotation Solver MulitpartFile Resolves to Null

I have a Spring custom annotation which I am using instead of #requestParam
public Response uploadImages(#myResolver(value = "imageFile", required = true) final MultipartFile multiPartFile) {...}
However, the mulitpart file parameter is resolved to null. So I put a breakpoint in my HandlerMethodArgumentResolver.resolveArgument to see if the argument was being resolved, but the breakpoint is never reached. But I know my custom annotation works for other params such as String, long e.t.c.
When I try using #requestParam instead it works fine, and the multipart file is resolved.
public Response uploadImages(#requestParam(value = "imageFile", required = true) final MultipartFile multiPartFile) {...}
Does anyone know why mulitpart file is being resolved to null using my custom parameter resolver and not using resolveArgument and how I could solve this please?
Thanks!
EDIT
The config for adding argument resolvers
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
super.addArgumentResolvers(argumentResolvers);
argumentResolvers.add(new MyAnnotationResolver());
}
My annotation definition
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#Component
public #interface MyResolver{
String value() default "";
boolean required() default true;
String defaultValue() default ValueConstants.DEFAULT_NONE;
String errorCode() default "40000";

DTO has only null with GET request params, but not POST #RequestBody

I'm trying to get my query params in a DTO like in this question but my DTO has always null value.
Is there anything wrong in my code ? I made it as simple as possible.
Queries:
GET http://localhost:8080/api/test?a=azaz => null
POST http://localhost:8080/api/test with {"a":"azaz"} => "azaz"
Controller with a GET and a POST:
#RestController
#RequestMapping(path = {"/api"}, produces = APPLICATION_JSON_VALUE)
public class MyController {
// GET: dto NOT populated from query params "?a=azaz"
#RequestMapping(method = GET, path = "test")
public #ResponseBody String test(TestDto testDto){
return testDto.toString(); // null
}
// POST: dto WELL populated from body json {"a"="azaz"}
#RequestMapping(method = POST, path = "test")
public #ResponseBody String postTest(#RequestBody TestDto testDto){
return testDto.toString(); // "azaz"
}
}
DTO:
public class TestDto {
public String a;
#Override
public String toString() {
return a;
}
}
Thanks !
Full Spring boot sample to illustrate it
The problem is that you are missing setter for the field.
public void setA(String a) {
this.a = a;
}
should fix it.
I'm assuming that you have done required configuration like having Jackson mapper in the class path, consume json attribute, getter and setter in DTO classes etc.
One thing missed here is, in RequestMapping use value attribute instead of path attribute as shown below
#RequestMapping(method = POST, value= "/test", consumes="application/json")
public #ResponseBody String postTest(#RequestBody TestDto testDto){
return testDto.toString();
}
And, make sure that you set content-type="application/json" while sending the request
I think what you are trying to do is not possible. To access the query Parameter you have to use #RequestParam("a"). Then you just get the String. To get your object this way you have to pass json as Parameter. a={"a":"azaz"}
Kind regards

Map #CookieValue, #RequestHeader etc. to POJO in Spring Controller

I have a bunch of params in my controller and want to map all of them to a separate POJO to keep readability. There is also a #CookieValue, #RequestHeader I need to evaluate and aim for a solution to also map them to that POJO. But how?
I saw a possible solution on a blog but it doesn't work, the variable stays null.
Controller:
#RequestMapping(path = MAPPING_LANGUAGE + "/category", produces = MediaType.TEXT_HTML_VALUE)
#ResponseBody
public String category(CategoryViewResolveModel model) {
doSomething();
}
And my POJO is this:
public class CategoryViewResolveModel {
private String pageLayoutCookieValue;
public CategoryViewResolveModel() {
}
public CategoryViewResolveModel(
#CookieValue(value = "SOME_COOKIE", required = false) String pageLayoutCookieValue) {
this.pageLayoutCookieValue = pageLayoutCookieValue;
}
... some other RequestParams, PathVariables etc.
}
According to the documentation it's not possible for #CookieValue and #RequestHeader.
This annotation is supported for annotated handler methods in Servlet
and Portlet environments.
Take a look at:
https://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-creating-a-custom-handlermethodargumentresolver/
instead of using getParameter to access request parameters you can use getHeader to retrieve the header value and so define your CategoryViewResolveModel just as you were requesting

Resources