[뉴스피드 프로젝트] 프로필 수정하기 / HTTP PATCH

말하는 감자·2025년 4월 9일

내일배움캠프

목록 보기
38/73

프로필 한 김에 다른 프로필 기능도 하려고함..!!
이때까지 수정을 put 으로 많이 했는데
아무래도 put은 전체 수정 (게시글 수정같은?)에 걸맞다보니
patch를 사용하려고한다.

put과 patch의 차이점을 알아보고 어떤식으로 서비스단에서 처리하면 좋을 지 고민해보자

🧐 PUT vs PATCH 차이

PUT 과 PATCH는 둘 다 리소스를 업데이트할 때 사용한다.
이 둘의 큰 차이점으로 동작 방식을 들 수 있다.

PUT:

기존 리소스를 완전히 대체한다.

요청 본문에서 제공하지 않은 속성들은 기본적으로 null 또는 초기 상태가 될 수 있다.

예를 들어, 이름, 성별, 소개글을 포함한 사용자 프로필을 수정하려면 모든 필드를 요청에 제공해야 한다.

PATCH:

리소스의 일부 속성만 변경합니다.

본문에서 제공되지 않은 속성은 기존 값을 유지한다.

유연한 업데이트가 가능하며, 일부 속성 값이 null일 가능성도 있어 이를 처리해야 한다.

예를 들어, 사용자가 이름만 변경하려고 할 경우, 본문에 이름만 포함해도 동작합니다

예시

우리는 프로필 수정해야하느넫,
프로필에서 수정가능한 것이 이름, 성별, 소개글, 비밀번호 이다.

기존 row에서는 아래처럼 생겼다고 생각해보자

{
    "name": "김이름",
    "gender": 1,
    "introduction": "젠더에 1번은 남자야",
	"password" : "password123"
}

소개글만 바꿔보겠다.

PUT과 PATCH에 PEQUESTBODY를 아래와같이 설정해주겠다.

{
	"introduction": "소개말을 바꾸다."
}

PUT인 경우

{
    "name": NULL,
    "gender": NULL,
    "introduction": "소개말을 바꾸다.",
	"password" : NULL
}

PATCH인 경우

{
    "name": "김이름",
    "gender": 1,
    "introduction": "소개말을 바꾸다.",
	"password" : "password123"
}

이렇게된다.

그러니 PATCH를 활용하면되겠지??






작업 과정

솔직히 짜는 코드가 막 어렵고 그런건아닌데 제대로된 협업을 처음해봐서 허우적거리는 시간이 긴 것 같다.

Controller에서도 jwt처음쓰다보니 다른팀원분이 만들어주신 jwtProvider 클래스 살펴보는데 시간좀 걸렸고
dev브랜치에서 받아와서 일어나는 충돌을 해결하는 시간도 만만치않았다;

결과창


테이블 변동

SA에서 컨펌받은대로 테이블이 두개 더 늘어났고,
로그인할떄 리프레시 토큰발급을 위해 USER 테이블에 컬럼이 하나더 추가되었다.




📌 컨트롤러에 많은 일을 주지말자

컨트롤러가 해야하는 일은 딱 3가지만있따.
1. HTTP 호출받기
2. 서비스단에 변수 넘겨주기
3. RESPONSE하기

나머진 모두 서비스에서 하는거지 컨트롤러에서 일시키지말자




controller

    @PatchMapping("/profile")
    public ResponseEntity<UserResponseDto.UpdateProfile> updateProfile(
        @AuthenticationPrincipal UserDetails userDetails,
        @RequestBody @Valid UserRequestDto.UpdateProfile profile
    ) {
        return ResponseEntity.status(HttpStatus.OK)
            .body(userService.updateProfile(Long.parseLong(userDetails.getUsername()), profile));
    }

여기서 이번에 새롭게 알게되고 신경썻던 부분이 3가지가있다.
우선 이너클래스이다.

UserRequestDto.UpdateProfile 처럼 클래스 안에 클래스를 만들어서
클래스 이름이 좀더 직관적이게 보인다는 장점이있다.
저것만 봐도 아~ updateprofile을 하기위한 requestDto구나 하고 알게되는걱시다
따로 dto를 계속 만들필요도 없고 안에 쌓으면되니깐 편한것 같다.

두번째는 @AuthenticationPrincipal 사용하기...
이부분은 스프링 시큐리티를 직접 작성하신 팀원분이 수정해준 부분인데,

토큰에 커스텀으로 데이터를 받아서 토큰 스트링을 직접 해체하는 단계없이
get 함수로 바로 정보를 받아올 수 잇다는 점이다.
엄청 편하구먼!

세번쨰는 리턴하는 형식인데
기존>
return new ResponseEntity<>(반환값, HttpsStatus.ok)

변경점>
return ResponseEntitty.status(HttpsStatus.OK).body(반환값)
이렇게 변경되면서, 반환값의 내용이 길어져도 확실히 가독성 개선이 된 것같다.

Service

   @Transactional
    @Override
    public UserResponseDto.UpdateProfile updateProfile(Long userId, UpdateProfile profile) {
        User user = userRepository.findByUserIdOrElseThrow(userId);

        if (profile.getName() != null) {
            user.setName(profile.getName());
        }
        if (profile.getIntroduction() != null) {
            user.setIntroduction(profile.getIntroduction());
        }
        if (profile.getGender() != null) {
            user.setGender(profile.getGender());
        }

        if (profile.getPassword() != null && !PasswordEncoder.matches(profile.getPassword(),
            user.getPassword())) {
            user.setPassword(PasswordEncoder.encode(profile.getPassword()));
        }

        if (profile.getIsPublic() != null) {
            user.setPublic(profile.getIsPublic());
        }

        User savedUser = userRepository.save(user);
        return new UserResponseDto.UpdateProfile(savedUser);
    }

이부분은 뭐 .. 그냥했다.
Patch값이다보니 하나하나 null 체크를 해줘야한다는 단점이있지만 사용자입장에서느 ㄴ이게 편하니깐!
비밀번호 교체도 잘된다.





테스트할때 겪었던 묹제

기존에서는 세션을 사용했었다. 로그인이 완료되면 자동으로 헤더에 세션값이 슝슝 나와서 편했는데, 토큰은 안그랬다..

로그인을 성공하면 이렇게
토큰 타입과 엑세스토큰, 리프레시 토큰을 발급받는다.

이걸 포스트맨에서 어떻게 활용하는지 몰라서 좀 헤맷는데
헤더에 하나하나 집어넣어줬다그냥..

Key값으로 Authorization넣어주고
Value로 토큰타입(Bearer) __^간격 1개^__ 엑세스 토큰 값 순서로 집어넣으면된다.

profile
대충 데굴데굴 굴러가는 개발?자

0개의 댓글