John's 개발자의 관심노트

Springboot REST API 구현하는 방법, Put Method 구현 (@PutMapping, @RestController) 본문

[개발]/Spring WEB

Springboot REST API 구현하는 방법, Put Method 구현 (@PutMapping, @RestController)

John-Co 2022. 10. 20. 18:00

오늘은 HTTP 의 "PUT" 기능을 구현해보는 예제다.

HTTP PUT 요청은 해당 요청 body 영역의 데이터를 사용해서 새로운 리소스를 생성하거나, 대상 리소스를 나타내는 데이터를 수정한다.

오늘 PUT 기능을 보면서 사용자 등록, 수정 등을 해볼 수 있지 않을까 해서

조잡하지만 그 기능을 테마로 예제를 구현해보려고한다.

 

먼저, 오늘 PUT 기능을 구현하면서 내가 사용한 어노테이션 (Annotation) 이다.

"@RestController" : 선언된 클래스를 REST API Controller 로 사용하겠다라는 의미
"@RequestMapping("/test/put")" : 해당 컨트롤러에 접근하기위한 URI 맵핑
"@PutMapping("/json")" : 컨트롤러내에 Method 에 접근하기위한 URI 맵핑
"@RequestBody UserData userData" : PUT 요청 시, 전달되는 body 영역을 담을 파라미터 
"@PathVariable (name="userid") Long userId" : PathVariable 을 담을 파라미터

이제 "PUT" 기능을 구현할 클래스를 "PutController" 로 작성했고,

이후 Class 위쪽에 어노테이션을 작성해서 REST API Controller로 작동되도록 지정했다.

해당 Controller 로에 접근을 위한 URI 맵핑은 "/test/put" 으로 지정했다.

@RestController
@RequestMapping("/test/put")
public class PutController {
    
}

이제 사용자의 정보는 JSON 데이터로 보낼 것이기 때문에, 예제 동작을 위한 JSON 데이터를 디자인해본다.

{
	"name" : "john-co",
	"age" : 10,
	"phone_number" : "010-1234-5671",
	"address" : "john-co@tistory.com"
}

JSON 과 관련한 내용은 아래 글에 있으니 궁금하다면, 아래 글을 통해 개발에 필요한 간략한 지식을 얻을 수 있다.

 

[SpringBoot] Springboot - "POST" API 구현하는 방법!

오늘은 HTTP 의 "POST" 기능을 Springboot 로 구현하는 예제를 작성해보려고한다. 📌HTTP "POST" 란? GET 방식과는 달리, POST 기능에서는 body 영역에 데이터를 실어 보낼 수 있다. GET 방식 또한, 데이터 전달

johnconomics.tistory.com

이제 위 JSON 데이터를 받을 DTO 클래스인 "UserDto" 를 생성해본다.

package com.example.httpapi.http.put.dto;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(value= PropertyNamingStrategy.SnakeCaseStrategy.class)
public class UserDto {
    private String name;
    private int age;
    private String phoneNumber;
    private String address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "UserDto{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", phoneNumber='" + phoneNumber + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

위 코드에서 팁이 있다면, "@JsonNaming(value=PropertyNamingStrategy.SnakeCaseStrategy.class)" 구문이다.

JSON 데이터에서 key 의 이름과, DTO 클래스 내의 변수 이름과 매칭이 되어야 하는데,

Snake Case 와 Camel Case의 사용으로 매칭이 안되는 경우가 있다.

이를 위해서 DTO 클래스 상단에 위 JsonNaming.... 이 구문을 써주면, 해당 클래스에서는 모든 변수이름을

SnakeCase 로 맵핑해서 사용하겠다 라는 의미를 가진다.

 

다시말해서, JSON 데이터에서 Key 값이 "phone_number" 형식의 snake case로 보내고,

코드에서는 "phoneNumber" 를 선언했을 때, 서로를 매칭시켜줄 수 있다.

 

이제 다음으로 "PUT" API 를 구현해보는데, 사용자를 저장할 수 있는 Map 객체를 선언해서,

PUT 요청 시, Query Variable 내에 User ID 를 받아서 해당 ID가 이미 등록되어 있다면 내용 수정을하고,

없다면 데이터를 신규 등록해주고, 그 결과를 반환하는 예제를 작성해봤다.

@RestController
@RequestMapping("/test/put")
public class PutController {
    private Map<Long, Object> userDataBase = new HashMap<>();

    @PutMapping("/json")
    public String PutRequest(@RequestParam Long userid, @RequestBody UserDto userDto){
        StringBuilder sb = new StringBuilder();

        UserDto existedData = (UserDto)userDataBase.get(userid);
        if(existedData != null){
            System.out.println("Update UserData !");
            existedData.setName(userDto.getName());
            existedData.setAge(userDto.getAge());
            existedData.setAddress(userDto.getAddress());
            existedData.setPhoneNumber(userDto.getPhoneNumber());
        }
        else{
            System.out.println("Create UserData !");
            userDataBase.put(userid, userDto);
        }

        // Show User Data
        userDataBase.forEach((uid, data)->{
            sb.append(String.format("%05d",uid) + " " + data + "\n");
        });
        System.out.println(sb.toString());

        return sb.toString();
    }
}

이제 웹 서버를 실행시키고, Talend API Tool 에서 아래와 같이 정보를 입력해서 PUT 요청을 보낸다.

위와 같이 데이터를 보내면, 아래 처럼 서버에서 로그가 나오고, 

Talend API Tool 에서 스크롤을 내려서 Response 응답을 확인하면 등록된 사용자 정보를 볼 수 있다.

추가적으로 Query 문의 userid 값을 변경해서 몇개 더 추가해보면,

이미 추가된 "userid=1" 의 Json data를 수정해서 보내면 아래와 같은 결과를 볼 수 있다.

임의의 Return Code 값 넘기기!

한 가지 팁을 더 추가하자면, Return Code 를 우리가 직접 제어할 수 있다.

정상적인 Put 요청을 받고, DataBody 를 기반으로 서비스를 처리하면서 잘 생성이 되었는지,

파라미터가 비정상적인것인지 등등을 확인하고 임의의 값으로 Return 할 수 있다.

 

Method 의 Return Type 을 "ResponseEntity<UserDto>" 로 변경하고,

Return 할 떄 잘 생성되었을 때 보내는 값인 "201" 을 응답하는 코드인

"return ResponseEntity.status(HttpStatus.CREATED).body(userDto);" 가 추가 된다.

@PutMapping("/json")
public ResponseEntity<UserDto> PutRequest(@RequestParam Long userid, @RequestBody UserDto userDto){
    StringBuilder sb = new StringBuilder();

    UserDto existedData = (UserDto)userDataBase.get(userid);
    if(existedData != null){
        System.out.println("Update UserData !");
        existedData.setName(userDto.getName());
        existedData.setAge(userDto.getAge());
        existedData.setAddress(userDto.getAddress());
        existedData.setPhoneNumber(userDto.getPhoneNumber());
    }
    else{
        System.out.println("Create UserData !");
        userDataBase.put(userid, userDto);
    }

    // Show User Data
    userDataBase.forEach((uid, data)->{
        sb.append(String.format("%05d",uid) + " " + data + "\n");
    });
    System.out.println(sb.toString());
	
    // CREATE 완료 값과, data body 영역에 업데이트 된 데이터를 실어서 응답
    return ResponseEntity.status(HttpStatus.CREATED).body(userDto);
}
반응형