Required Int and Boolean values in API payload - spring

I'm using Spring and Kotlin to create REST API. I have sample endpoint that looks like this
data class TestData(
#field:NotNull
val intValue: Int,
#field:NotNull
val booleanValue: Boolean
)
#RestController
#RequestMapping("/test")
class TestController {
#PostMapping
fun test(#RequestBody test: TestData) {
println(test)
}
}
And the issue is, I can send empty body in payload and in controller I'll recieve default values for Int and Boolean - TestData(intValue=0, booleanValue=false). How can I avoid that? Both 0 and false are valid values if provided by user, but I want him to explicitly pass them in request. If they are missing, I'd like to receive 400 bad request

Related

spring json serialization issue

I am unable to get is_secure object attribute in json response, what is wrong with this code ?
#Configuration
class RouterConfiguration( ) {
#Bean
fun testRoutes(testHandler: TestHandler) = coRouter {
GET("/test", testHandler::testFunction)
}
}
data class TestClass(
val is_secure: Int? = 1,
val xyz: String?
)
#Component
class TestHandler{
suspend fun testFunction(request: ServerRequest): ServerResponse =
ServerResponse.ok().bodyValueAndAwait(TestClass(1,"abc"))
}
is prefixed fields (with camelCase or snake_case pattern) are only serialized if they are of type Boolean. You can find more details about it here.
If you wish to keep the is prefix, you may do so by using #get use-site target. Just use #get:JsonProperty("is_secure") on the is_secure field and it should do.

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.

Does Springboot #RequestParam support List<Object> params in get request

Springboot #RequestParam annotation can pass basic list parameters, just like:
#GetMapping("param")
public String requestParamDemo(#RequestParam("list")List<Long> list) {
System.out.println(list.toString());
return list.toString();
}
and in postman, GET request localhost:8998/param?list=1,3,100 is works, "1,3,100" can be converted to List, but how or if Springboot #RequestParam support custom Generics such as below:
#GetMapping("objlist")
public String paramWithObjList(#RequestParam("objList")List<AaParam> objList) {
System.out.println("objList = " + objList);
return objList.toString();
}
import lombok.Data;
#Data
public class AaParam {
private int id;
private String name;
}
postman request: GET url: localhost:8998/objlist?objlist=[{id: 1, name: "aa"},{id: 2, name: "bb"}]
I tested in local and it didn't work.
Want to know if #RequestParam can do that or any alternative way to implement it.
Thanks!
Hope this suggestion holds good for your requirement.
I would suggest going with #RequestBody code will look like this
#PostMapping(path = "/objlist", consumes = "application/json", produces = "application/json")
public String paramWithObjList(#RequestBody List<AaParam> objList) {
System.out.println("objList = " + objList);
return objList.toString();
}
Note: please add some ObjectPaser in your actual logic (for example Jackson )
Postman request would be like this

Spring - Provide parsed JWT as Resource method parameter

In Spring framework, is there a way to parse JWT and provide it's data as one of the Resource method parameters?
Something like this:
class MyJwtToken {
String fieldA;
Integer fieldB;
}
public ResponseEntity<> create(
#JwtToken MyJwtToken token,
#RequestBody Item item
) {
item.setFieldA(token.getFieldA());
persist(item);
return ...;
}

Resources