6.7 블로그 글 수정 API 구현하기

SummerToday·2024년 2월 12일
1
post-thumbnail
post-custom-banner

서비스 메서드 구현

// domain - Article.java

@Entity // 엔티티로 지정
@Getter
@NoArgsConstructor
public class Article{
    
      ~ 생략 ~ 

    public void update(String title, String content) {
        this.title = title;
        this.content = content;
    }

}
  • 엔티티에 요청 받은 내용으로 값을 수정한다.

// dto - UpdateArticleRequest

@NoArgsConstructor
@AllArgsConstructor
@Getter
public class UpdateArticleRequest {
    private String title;
    private String content;

}
  • 블로그 글 수정 요청을 받을 DTO를 생성한다.

@RequiredArgsConstructor 
@Service 
public class BlogService {
    
    @Transactional
    public Article update(long id, UpdateArticleRequest request) {
        Article article = blogRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("not found : " + id));

        article.update(request.getTitle(), request.getContent());

        return article;
    }
}
  • @Transactional
    데이터베이스 트랜잭션을 처리하기 위해 Spring에서 제공하는 기능 중 하나이고, 매칭한 메서드를 하나의 트랜잭션으로 묶는 역할을 한다. (ex. 다수의 쿼리를 하나의 트랜잭션으로 묶어 처리하는 경우)

    Spring이 해당 메서드 또는 클래스 내의 모든 데이터베이스 작업을 하나의 트랜잭션으로 처리하여, 내부 로직 처리 중에 에러가 발생해도 제대로된 값의 수정을 보장 해준다.

    • Transaction
      트랜잭션이란, 데이터베이스의 데이터를 바뀌기 위해 묶은 작업의 단위이다
      트랜잭션은 안전성을 보장하기 위해 필요한 4가지 성질이 존재한다.

      • 원자성(Atomicity)
        트랜잭션이 실행될 때, 데이터베이스에 모두 반영되던가, 모두 반영되지 않아야 한다.

      • 일관성(Consistency)
        트랜잭션의 작업 처리 결과는 항상 일관성이 있어야 한다.

      • 독립성(Isolation)
        둘 이상의 트랜잭션이 동시에 실행될 때, 다른 트랜잭션의 연산에 끼어들 수 없다.

      • 지속성(Durability)
        트랜잭션이 성공적으로 완료되었을 경우, 결과는 영구적으로 반영이 되어야 한다.
    • 트랜잭션 사용 이유
      예를 들어, 계좌 이체를 할 때의 과정을 생각해보면, A 계좌에서 출금, B 계좌에서 입금 이 두 단계로 이루어진다.
      만약, 이 과정 중 A 계좌에서 출금만 이루어지고 B 계좌에 입금이 안된다면 심각한 상황이 발생하게 되니, 출금과 입금을 하나의 작업단위, 즉 트랜잭션으로 묶어 실행해줘야 한다는 것이다.
      이렇듯 한번에 이루어져야 하는 일련의 작업들을 하나의 단위로 묶어줘야 할 때 트랜잭션을 사용한다.

컨트롤러 메서드 구현

// controller - BlogApiController

@RequiredArgsConstructor
@RestController 
public class BlogApiController {

      ~ 생략 ~
   
    @PutMapping("/api/articles/{id}")
    public ResponseEntity<Article> updateArticle(@PathVariable long id,
                                                 @RequestBody UpdateArticleRequest request) {
        Article updatedArticle = blogService.update(id, request);

        return ResponseEntity.ok()
                .body(updatedArticle);
    }

}
  • 수정하고자 하는 글의 id와 수정한 글의 내용을 DTO로 받아 BlogService의 update 메서드에 전달 후 해당 Article 엔티티에 구현한 update() 메서드를 호출해 글 내용 수정 후, 200 OK 응답코드를 설정하고 바디에 수정된 글 정보를 담고 있는 객체를 반환한다.

    UpdateArticleRequest(dto) -> BlogApiController(controller)-> BlogService(service) -> Article(domain)


테스트 코드 작성

Given
: 블로그 글을 저장하고, 블로그 글 수정에 필요한 요청 객체를 만든다.

When
: UPDATE API로 수정 요청을 보낸다. 이때 요청 탕비은 JSON이며, given 절에서 미리 만들어둔 객체를 요청 본문으로 함께 보낸다.

Then
: 응답코드가 200 OK인지 확인 후 블로그 글 id로 조회한 후에 값이 수정되었는지 확인한다.

// test - BlogApiControllerTest.java

@SpringBootTest // 테스트용 애플리케이션 컨텍스트
@AutoConfigureMockMvc // MockMvc 생성
class BlogApiControllerTest {
    
      ~ 생략 ~
    
    @DisplayName("updateArticle: 블로그 글 수정에 성공한다.")
    @Test
    public void updateArticle() throws Exception {
        // given
        final String url = "/api/articles/{id}";
        final String title = "title";
        final String content = "content";

        Article savedArticle = blogRepository.save(Article.builder()
                .title(title)
                .content(content)
                .build());

        final String newTitle = "new title";
        final String newContent = "new content";

        UpdateArticleRequest request = new UpdateArticleRequest(newTitle, newContent);

        // when
        ResultActions result = mockMvc.perform(put(url, savedArticle.getId())
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(objectMapper.writeValueAsString(request)));

        // then
        result.andExpect(status().isOk());

        Article article = blogRepository.findById(savedArticle.getId()).get();

        assertThat(article.getTitle()).isEqualTo(newTitle);
        assertThat(article.getContent()).isEqualTo(newContent);
    }
}
  • objectMapper.writeValueAsString()
    Jackson ObjectMapper를 사용하여 Java 객체를 JSON 문자열로 변환하는 메서드이다.

    Java 객체를 JSON 문자열로 변환하는 이유는 HTTP 통신에는 JSON 형식이 사용되기 때문이다.

  • 추가 설명은 '4.3 테스트 코드' 참고




해당 글은 다음 도서의 내용을 정리하고 참고한 글임을 밝힙니다.
신선영, ⌜스프링 부트 3 벡엔드 개발자 되기 - 자바 편⌟, 골든래빗(주), 2023, 384쪽
profile
IT, 개발 관련 정보들을 기록하는 장소입니다.
post-custom-banner

0개의 댓글