Photo by Douglas Lopes on Unsplash
SpringPortal #2 - Responding to Request in Spring Boot
Handling request parameters and API response
Request To Response
Spring allows creating an API that handles input, processes it, and returns the output. This is similar to what a standard function in every programming language does. But an API contains more information and gives more control than a normal java function.
Annotations for API Request
1. @RequestParam
@GetMapping("/get")
public ResponseEntity<Object> get(@RequestParam String first,
@RequestParam(required = false) String second,
@RequestParam(required = false, defaultValue = "2") Integer third,
@RequestParam(required = false, name = "fourth") String fourthParam) {
log.info("First = {} | Second = {} | Third = {} | Fourth = {}", first, second, third, fourthParam);
// empty response with 200 success code
return ResponseEntity.ok().build();
}
@RequestParam
annotation maps the parameter in the API to the function parameter.If the parameter name in the API and function parameter name is the same, it maps directly.
?first=Java
will assign the value "Java" to the function parameter first.
But if the parameter
first
is not supplied in the request, then API will throw an error similar to this:
- The API has thrown an error:
Required request parameter 'first' for method parameter type String is not present - This is because the API requires the parameter
first``` in the request.
Now, let's try another API call: -
http://localhost:8080/request/get?first=Spring&fourth=Portal
This is what Spring has printed in the logs: -
c.s.hellospring.api.RequestResponseApi : First = Spring | Second = null | Third = 2 | Fourth = Portal
You will notice that there is no response on the page but the log is showing the correct picture.
The params are behaving as follows:
first is the required parameter and it is exactly equal to what we've sent in the API.
second is marked
@RequestParam(required = false)
which allows the parameter to be null if it is skipped in the API call.For a parameter to be null, please note, it needs to be of object type, instead of primitive type.
third is marked
@RequestParam(required = false, defaultValue = "2")
to make it optional in the API and set its default value to be 2.The defaultValue needs to be a valid string that can be parsed by Java into a required object.
fourth is similar to the earlier parameter, just the API will accept the name "fourth" and map it to the function parameter "fourthParam".
2. @RequestBody
@PostMapping("/getPersonBody")
public ResponseEntity<?> getOptionalBody(@RequestBody(required = false) Person person) {
if (person == null) {
return ResponseEntity.ok(Map.of(
"defaultResponsePerson",
Person.builder()
.firstName("Response")
.lastName("Person")
.build()
));
}
// response with code 418
return ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).body(person);
}
@RequestBody
annotation indicates the object into which the HttpRequest body JSON object should get deserialized into.While sending the POST request from Postman, it will look like this,
{ "id": 1234, "firstName": "Spring", "lastName": "Portal", "dob": "2022-11-04T20:30:50.010+00:00" }
Spring will map this JSON object to the specified object in the function which is marked with
@ResponseBody
annotation.This is also optional and can be null, which can be achieved by specifying
required = false
in the annotation.
What about responses?
ResponseEntity
ResponseEntity is a class provided by spring to represent the HTTP response.
It helps in setting three important params: Headers, Status Code & Body.
- Empty Response
@GetMapping("/get") public ResponseEntity get(@RequestParam String first, @RequestParam(required = false) String second, @RequestParam(required = false, defaultValue = "2") Integer third, @RequestParam(required = false, name = "fourth") String fourthParam) {
log.info("First = {} | Second = {} | Third = {} | Fourth = {}", first, second, third, fourthParam);
// empty response with 200 success code
return ResponseEntity.ok().build();
}
> ```ResponseEntity.ok().build()``` will return a response with success code 200 and an empty body.
- Response with Body
@GetMapping("/getBody")
public ResponseEntity<Person> getBody(@RequestBody Person person) {
log.info("Person object recieved -> {}", person);
// response with 200 success code and a body
return ResponseEntity.ok(person);
}
ResponseEntity.ok(person)
will return a response with success code 200 and a body.
- Response with Body and required status code
@PostMapping("/getPersonBody")
public ResponseEntity<?> getOptionalBody(@RequestBody(required = false) Person person) {
if (person == null) {
return ResponseEntity.ok(Map.of(
"defaultResponsePerson",
Person.builder()
.firstName("Response")
.lastName("Person")
.build()
));
}
// response with code 418
return ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).body(person);
}
ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).body(person)
lets you set required status along with the body.
@ResponseBody
annotation with custom headers
@ResponseBody
@GetMapping("/getPersonResponse")
public Person getPersonResponse() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Request-UUID", UUID.randomUUID().toString());
return Person.builder()
.firstName("Response")
.lastName("Person")
.build();
}
```@ResponseBody``` annotation lets you replace the return type ```ResponseEntity``` with ```Person```.
It'll allow Spring to convert ```Person``` object to a JSON object for returning in the API request.
Note:
HttpHeaders
allows setting custom headers to the response.Here we've set
Request-UUID
which allows us to mark the API with a unique identifier.In the future, we'll explore how this ID is used to track the API logs across the application along with MDC.