게시글 수정
이제 CRUD 의 R 까지 했으니 이젠 U 차례다.
게시글 수정은 JPA 의 변경감지를 이용해서 구현해보자.
PostController
데이터를 서비스로 넘겨준 후 수정된 Post 데이터를 반환한다.
@PatchMapping("/posts/{postId}")
public PostResponse edit(@PathVariable Long postId, @RequestBody @Valid PostEdit request) {
return postService.edit(postId, request);
}
ㄴ @PathVariable
URL 쿼리 파라미터로 Post 의 id 값을 받는다.
ㄴ @RequestBody
JSON 요청으로 PostEdit 객체에 데이터를 담는다
PostEdit
PostCreate 와 거의 같으니까 이걸로 퉁치면 안되나? 라고 생각할 수 있지만 그러다간 큰일날수있다.
기능이 다르면 구조가 비슷해도 명확하게 분리하는걸 절대적으로 추천한다.
지금은 비슷할지라도 나중엔 완전히 달라질 수가 있으니 그때 가서 고치려고 하면 굉장히 골아프다.
@Getter
@NoArgsConstructor
public class PostEdit {
@NotBlank(message = "제목을 입력해주세요.")
private String title;
@NotBlank(message = "내용을 입력해주세요.")
private String content;
@Builder
public PostEdit(String title, String content) {
this.title = title;
this.content = content;
}
}
PostService
컨트롤러로 부터 받은 데이터로 수정을 진행하고 컨트롤러로 수정된 Post 데이터를 반환한다.
@Transactional
public PostResponse edit(Long id, PostEdit request) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 글입니다."));
post.edit(request.getTitle(), request.getContent());
return new PostResponse(post);
}
ㄴ @Transactional
트랜잭션을 적용한다는 애노테이션이다.
JPA 의 변경감지를 이용하면 별도의 리포지토리 저장 메서드 호출없이 트랜잭션만 걸어줘도
트랜잭션이 끝날 때 자동으로 엔티티의 변경 값이 업데이트 된다.
Post
Post 엔티티 내에 수정 메서드를 내장해 캡슐화한다.
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@Lob
private String content;
@Builder
public Post(String title, String content) {
this.title = title;
this.content = content;
}
public void edit(String title, String content) {
this.title = title;
this.content = content;
}
}
PostServiceTest
글 내용은 그대로 두고 제목만 변경 시 기대한대로 동작하는지 확인하는 테스트를 작성한다.
@DisplayName("글 제목 수정")
@Test
void edit() {
// given
Post post = Post.builder()
.title("우리 이쁜 미카공주님")
.content("우리 공주님")
.build();
postRepository.save(post);
PostEdit request = PostEdit.builder()
.title("사랑스러운 공주님")
.content("우리 공주님") // 이 부분은 client 와의 상의가 필요
.build();
// when
postService.edit(post.getId(), request);
Post changedPost = postRepository.findById(post.getId())
.orElseThrow(() -> new RuntimeException("글이 존재하지 않습니다. id = " + post.getId()));
// then
assertEquals(1L, postRepository.count());
assertEquals("사랑스러운 공주님", changedPost.getTitle());
assertEquals("우리 공주님", changedPost.getContent());
}
테스트 수행 시 우리가 원했던 대로 동작하며 테스트가 성공함을 알 수 있다.
PostControllerTest
글 내용은 그대로 두고 제목만 변경 시 기대한대로 동작하는지 확인하는 테스트를 작성한다.
@DisplayName("글 제목 수정")
@Test
void edit() throws Exception {
// given
Post post = Post.builder()
.title("우리 이쁜 미카공주님")
.content("우리 공주님")
.build();
postRepository.save(post);
PostEdit request = PostEdit.builder()
.title("사랑스러운 공주님")
.content("우리 공주님")
.build();
// expected
mockMvc.perform(
MockMvcRequestBuilders.patch("/posts/{postId}", post.getId())
.contentType(APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request))
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.title").value("사랑스러운 공주님"))
.andExpect(jsonPath("$.content").value("우리 공주님"))
.andDo(print());
}
테스트 수행 시 우리가 원했던 대로 동작하며 테스트가 성공함을 알 수 있다.
고민해볼점
이 글에서 작성한 방식은 수정할 필드 외의 데이터를 보내지 않을 시 나머지 부분은 null 이 될 수 있다.
수정 시 Client 측에서 서버로 데이터를 어떻게 보내냐에 따라 수정 메서드를 고쳐야할 필요가 있다.
- 수정할 필드 데이터만 보내냐
- 수정할 필드 및 그대로인 필드 데이터 다 보내냐
'API 만들어 보기 > 게시판 API' 카테고리의 다른 글
[예외처리] 예외처리 1 (0) | 2023.09.26 |
---|---|
[게시글 삭제] 게시글 삭제 (0) | 2023.09.26 |
[게시글 조회] 페이징 처리 - Querydsl (0) | 2023.09.25 |
[게시글 조회] 페이징 처리 1 (0) | 2023.09.25 |
[게시글 조회] 게시글 여러개 조회 (0) | 2023.09.24 |