수정 기능의 테스트를 만들고 기능을 구현해보자.
수정 기능의 수행 과정은 다음과 같다.
- HTTP 메서드는 PUT메서드를 사용한다.
- urn은 /free-board/{free-board-id}를 사용한다.
- FreeBoardController#putFreeBoard(long freeboardId, FreeBoardDto dto); 메서드에서 Put DTO를 받아와 FreeBoard Serivce에 넘겨주고 Response DTO를 받아온다.
- 받아온 Response DTO를 ResponseEntity객체로 변환해 반환한다. 이 때, HttpStatus는 OK로 설정한다.
수정에 PATCH 대신 PUT 메서드를 사용하는 이유는 다음과 같다.
- 우리가 정보 수정을 하는 경우를 생각해보면, 특정한 블록만 수정 할 수 있게 화면이 제공되는 경우는 거의 없다. 수정 할 수 있는 거의 모든 정보가 열린다.
- 특히 게시판의 경우에는 제목, 내용, 말머리 등 처음 작성할 때 등록하는 정보를 전부 수정할 수 있게 전달하는 경우가 많다.
- 이런 정보들을 클라이언트에서 어느 것은 바뀌었고, 바뀌었지 않았는지를 판단하는 것보다는 그냥 통째로 보내고 전부 받아서 수정하는 것이 낫다.
- PATCH와 PUT의 멱등성 차이도 고려한 결과라고 하면 좋겠지만 거기까지는 아니다. 다만 왜 PATCH는 멱등하지 않고 PUT은 멱등한지는 알아두자.
- PATCH는 '수정'을 명령하는 메서드가 아니다. '수정에 대한 지시'를 내린다.
- 만일 '수정'이라는 행위가 '추가'라면 어떨까? 예를 들어, 게시글 전체라는 자원에 '게시글 추가'를 넣는다고 생각해보자. 추가하는 행위도 결국은 '게시글 전체를 수정' 하는 것 아닌가?
- 이런 명령 행위를 담은 PATCH를 여러 번 수행하면, 계속해서 추가가 이루어지기 때문에 멱등하지 않다.
- 반면 PUT은 '대체'다. 몇 번을 수행해도 당연히 같은 결과가 만들어진다. 멱등하다.
- 관련해서 참고할만한 링크들을 글 말미에 남긴다.
아무튼 테스트를 만들어보자. 사실 작성 테스트를 만들 때와 크게 다르지 않다. 테스트 코드는 붙여넣기 수준으로 작성됐다. 차이가 있다면 HttpStatus 코드를 OK로 설정했으니 이를 바꿔준다는 점이 있다. 또한 urn에 id값을 추가해준다.
@Test
@DisplayName("정상적인 게시글 수정 요청 테스트")
void putFreeBoardTest() throws Exception {
// given
String testTitle = "changedTitle";
String testContent = "changedContent";
long testId = 1L;
FreeBoardDto.Put testPut = new FreeBoardDto.Put();
testPut.setTitle(testTitle);
testPut.setContent(testContent);
FreeBoardDto.Response testResponse = FreeBoardDto.Response
.builder()
.title(testTitle)
.content(testContent)
.build();
String content = gson.toJson(testPut);
given(freeBoardService.putFreeBoard(anyLong(), any())).willReturn(testResponse);
// when // then
mockMvc.perform(
put("/free-board/" + testId)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(content)
).andExpect(status().isOk())
.andExpect(jsonPath("$.title").value(testPut.getTitle()))
.andExpect(jsonPath("$.content").value(testPut.getContent()));
}
위 테스트는 통과하지 못 한다. 컨트롤러에 기능 구현을 아예 해놓지 않았다. 테스트를 기반으로 기능을 구현해보자.
@PutMapping("/{free-board-id}")
public ResponseEntity<FreeBoardDto.Response> putFreeBoard(@PathVariable("free-board-id") long freeBoardId,
@RequestBody FreeBoardDto.Put dto){
FreeBoardDto.Response responseDto = freeBoardService.putFreeBoard(freeBoardId, dto);
return new ResponseEntity<>(responseDto, HttpStatus.OK);
}
사실 뭐 딱히 테스트를 기반으로 구현한다고 할만큼 대단한 건 없다. 다만, 반환하는 Response Entity에 HttpStatus코드에 OK를 적용한다는 것만 신경쓰자.
이렇게 수정 기능의 구현을 마무리했...다... 고 하기에는 뭔가 기능 구현 자체는 크게 한 게 없는 느낌이긴 하다. 뭐 세부적인 로직은 서비스 계층 구현 때 해놨고, 테스트 로직도 크게 다른 점이 없으니 그러려니 싶다. 게시글 조회나 삭제는 굳이 포스팅까지 할 내용은 아닌 것 같다. 테이블 디자인을 다시 할 때나 아니면 아예 다른 기능들을 만들 때 다시 포스팅할까 싶다.
전체 코드는 링크에서 확인할 수 있다.
읽어 볼만한 자료들
qu3vipon님 블로그 - PATCH는 정말 멱등하지 않을까?
PATCH는 정말 idempotent 하지 않을까?
Intro
www.qu3vipon.com
Tecoble - 자원을 수정하는 HTTP 메서드 PUT vs PATCH
자원을 수정하는 HTTP 메서드 - PUT vs PATCH
들어가며 웹 API를 설계할 때, 최대한 Http 표준을 따라서 용도에 맞는 Http Method를 사용해야 한다는 것은 아마 많은 개발자들이 인지하고 있을 것이다. 이번 글에서는 Http Method…
tecoble.techcourse.co.kr
Use of PUT vs PATCH methods in REST API real life scenarios
Use of PUT vs PATCH methods in REST API real life scenarios
First of all, some definitions: PUT is defined in Section 9.6 RFC 2616: The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an a...
stackoverflow.com
'Programming > TDD Project' 카테고리의 다른 글
Pull Request 015. API 문서화 적용하기 - Spring Rest Docs (2) | 2023.11.28 |
---|---|
Pull Request 014. 게시판 테이블 상속하기 (0) | 2023.11.27 |
Pull Request 012 - 자유 게시글 등록 기능 컨트롤러 계층 TDD로 구현하기 (0) | 2023.11.20 |
Pull Request 011 - 자유게시글 삭제 기능 TDD로 구현해보기 (1) | 2023.11.11 |
Pull Request 010 - 자유게시글 조회 기능 TDD로 구현해보기 (0) | 2023.11.10 |
댓글