REST API - PUT

Seunghwan Choi·2024년 10월 28일

Java Backend

목록 보기
4/16

PUT vs POST

  1. Purpose
    • POST: Used to create a new resource on the server
      - When a POST request is sent, server will add a new resource, typically without specifying its URI. The server often generates a unique identifier for the resource and returns it in the response.
    • PUT: Used to update an existing resource or create a new resource at a specified URI
      - With PUT, we typically provide the full data for the resource and specify its location. If the resource exists, it is replaced with the data in the request. If it doesn't exist, the server may create a new resource at that specified URI.
  2. Idempotency
    • POST: Not idempotent
      - Repeated POST requests create multiple resources if the server is configured to allow it.
    • PUT: Idempotent
      - Repeated PUT requests with the same data do not change the result beyond the first request. If we PUT the same data to the same URI multiple times, it overwrites the existing resource, yielding the same state each time.

Example

@RestController
@RequestMapping("/api")
@Slf4j
public class PutApiController {
    @PutMapping("/put")
    public void put(
            @RequestBody UserRequest userRequest
            ){
        log.info("Request: {}", userRequest);
    }
}
  • When we send a PUT request to the below URI,
http://localhost:8080/api/put

//body:
{
  "user_name": "Choi Seunghwan",
  "user_age": 15,
  "email": "choi12345@gmail.com",
  "is_Korean": true
}

we get

2024-10-28T21:00:46.617+09:00  INFO 9404 --- [rest-api] [nio-8080-exec-8] c.e.r.controller.PutApiController        : Request: UserRequest(userName=Choi Seunghwan, userAge=15, email=choi12345@gmail.com, isKorean=false)

Above, isKorean in the log is "false" although in the body of the request it was stated as true. isKorean in "UserRequest" is a boolean type. The automatically generated set method for "isKorean" field by Lombok is setKorean(), not setIsKorean(), hence the mismatch.

We can solve this with 2 methods:
1. Modifying the key field in json body:

    {
     "user_name": "Choi Seunghwan",
     "user_age": 15,
     "email": "choi12345@gmail.com",
     "Korean": true
    }
  • This will invoke setKorean() method generated by Lombok, and the output would be:
    UserRequest(userName=Choi Seunghwan, userAge=15, email=choi12345@gmail.com, isKorean=true)
  • But this might distort the meaning in the client side.
  1. Changing from boolean to Boolean (primitive to wrapper class)
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
    public class UserRequest {
        private String userName;
        private Integer userAge;
        private String email;
        private Boolean isKorean; //default is false
    }
    • This will cause Lombok to re-generate the setter method for isKorean to:
    • For boolean fields, Java conventionally names the getter/setter method with the prefix is. So, for a field named isKorean, Lombok generates isKorean() as the getter and setKorean() as the setter.
    • For Boolean fields, since Boolean is an object rather than a primitive, Java treats it like any other object type (e.g. String, Integer). The setter method will now be prefixed with set rather than is.
    • Consequently, we get the desired output even without modifying the json body:
    //json
    {
      "user_name": "Choi Seunghwan",
      "user_age": 15,
      "email": "choi12345@gmail.com",
      "is_korean": true
    }
    //output
    UserRequest(userName=Choi Seunghwan, userAge=15, email=choi12345@gmail.com, isKorean=true)
    • And since boolean can't take null as its value but Boolean can, even the "value" is empty in the json, it will not trigger an error but simply be mapped as null, which might be a desired behaviour in certain cases.

0개의 댓글