Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I need a separate object for every @RequestBody in Spring Boot

So far I have done one (REST) project using Spring Boot and liked it a lot. The one thing I found to be somewhat devious was my understanding of @RequestBody.

Suppose I have the POST method below to login a user. My user entity may contain attributes other than just the username and password I'd like the post-request to have. In this case I saw no other option but to make an extra object (LoginRequest) to hold the data for the incoming data.

@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<User> login(@RequestBody LoginRequest request) {
        User p = null;
        if (request != null) {
            p = User.login(request.getEmail(), request.getPassword()); // validates and returns user if exists
            if (p != null){
                return new ResponseEntity<User>(p, HttpStatus.OK);
            }
        }

        throw new IllegalArgumentException("Password or email incorrect");
    }

Similarly, I'd like the @ResponseBody to return a minimized version of the User object where for example the password is excluded.

What are some of the standard approaches to this issue? Do I really have to make a separate object for every 'json-view'? I did some REST stuff in python before and here I would just have a Dictionary containing the request attributes. Any similar approaches?

like image 457
Karim Stekelenburg Avatar asked May 24 '17 14:05

Karim Stekelenburg


2 Answers

  1. Create a new entity if you will persist or operate on it

  2. If you need a custom view for existing entity (add/remove fields) DTO with custom serialization can be used

  3. There maybe a case when you don't want to create DTO because you will not reuse it anywhere, but need some quick solution for custom response you can use Map<String, Object> - the key will be used for JSON field name, and Object is for the value, for example:

    @RequestMapping(method = RequestMethod.POST) public Map<String, Object> login(@RequestParam Integer p1) { Map<String, Object> map = new HashMap<>(); map.put("p1", p1); map.put("somethingElse", "456"); return map; }

JSON response:

{
  "p1": p1value,
  "somethingElse": "456"
}

3rd case will suite you if you're not building too complex bodies with nested objects which should be customized based on some conditions. Use 2nd option in the opposite case.

like image 172
J-Alex Avatar answered Sep 18 '22 23:09

J-Alex


There are two approaches to this, for both Request and Response -
1. Use Same entities with extra params and populate only what you need. You can check for nulls.
2. Use separate Data Transfer Objects (DTOs) - These basically can be used when entities have different fields than the object you need to transfer.

Personally, I like the first approach to save the effort of mapping entities to DTOs and back. But, sometimes when DTOs need to be totally different, we need to use the second approach. Eg. APIs for dashboards numbers and reports.

HTH

like image 43
Medha Avatar answered Sep 16 '22 23:09

Medha