SpringPortal #2 - Responding to Request in Spring Boot

Handling request parameters and API response

·

4 min read

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:

Screenshot 2022-11-04 00:25:39.png

  • 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 parameterfirst``` 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.


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

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


GitLab

Code Repository

Article-specific commit

Did you find this article valuable?

Support Naman Jain by becoming a sponsor. Any amount is appreciated!