[이벤트 조회 및 수정 REST API 개발]_03_Event 수정 API
Events 수정 API
테스트 할 것
수정하려는 이벤트가 없는 경우 404 NOT_FOUND
입력 데이터 (데이터 바인딩)가 이상한 경우에 400 BAD_REQUEST
도메인 로직으로 데이터 검증 실패하면 400 BAD_REQUEST
(권한이 충분하지 않은 경우에 403 FORBIDDEN)
정상적으로 수정한 경우에 이벤트 리소스 응답
- 200 OK
- 링크
- 수정한 이벤트 데이터
4가지 경우에 대한 테스트 추가
@Test
@TestDescription("이벤트를 정상적으로 수정하기")
public void updateEvent() throws Exception {
// Given
Event event = this.generateEvent(200);
EventDto eventDto = this.modelMapper.map(event, EventDto.class);
String eventName = "Update Event";
eventDto.setName(eventName);
// When & Then
this.mockMvc.perform(put("/api/events/{id}", event.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(this.objectMapper.writeValueAsString(eventDto))
)
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("name").value(eventName))
.andExpect(jsonPath("_links.self").exists());
}
@Test
@TestDescription("입력값이 비어있는 경우에 이벤트 수정 실패")
public void updateEvent400_Emtpy() throws Exception {
// Given
Event event = this.generateEvent(200);
EventDto eventDto = this.modelMapper.map(event, EventDto.class);
String eventName = "Update Event";
eventDto.setName(eventName);
// When & Then
this.mockMvc.perform(put("/api/events/{id}", event.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(this.objectMapper.writeValueAsString(eventDto)))
.andDo(print())
.andExpect(status().isBadRequest());
}
@Test
@TestDescription("입력값이 잘못된 경우에 이벤트 수정 실패")
public void updateEvent400_Wrong() throws Exception {
// Given
Event event = this.generateEvent(200);
EventDto eventDto = this.modelMapper.map(event, EventDto.class);
eventDto.setBasePrice(20000);
eventDto.setMaxPrice(1000);
// When & Then
this.mockMvc.perform(put("/api/events/{id}", event.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(this.objectMapper.writeValueAsString(eventDto)))
.andDo(print())
.andExpect(status().isBadRequest());
}
@Test
@TestDescription("존재하지 않는 이벤트 수정 실패")
public void updateEvent404() throws Exception {
// Given
Event event = this.generateEvent(200);
EventDto eventDto = this.modelMapper.map(event, EventDto.class);
// When & Then
this.mockMvc.perform(put("/api/events/123123")
.contentType(MediaType.APPLICATION_JSON)
.content(this.objectMapper.writeValueAsString(eventDto)))
.andDo(print())
.andExpect(status().isNotFound());
}
⇒ 테스트를 먼저 만들고 새로 생성한 테스트가 모두 깨지는지 확인하고(테스트가 잘 만들어졌는지) 로직 구현
이벤트 수정 API 구현
@PutMapping("/{id}")
public ResponseEntity updateEvent(@PathVariable Integer id,
@RequestBody @Valid EventDto eventDto,
Errors errors) {
Optional<Event> optionalEvent = this.eventRepository.findById(id);
if (optionalEvent.isEmpty()) {
return ResponseEntity.notFound().build();
}
if (errors.hasErrors()) { // Dto 바인딩 Validation error 확인
return badRequest(errors);
}
this.eventValidator.validate(eventDto, errors); // 로직 Validation 확인
if (errors.hasErrors()) {
return badRequest(errors);
}
Event existingEvent = optionalEvent.get(); // 기존 data
// update하려는 값은 eventDto에 들어있다. existingEvent의 값을 eventDto의 값으로 맵핑
this.modelMapper.map(eventDto, existingEvent);
Event savedEvent = this.eventRepository.save(existingEvent);
EventResource eventResource = new EventResource(savedEvent);
eventResource.add(Link.of("/docs/index.html#resources-events-update").withRel("profile")); // profile 링크 추가
return ResponseEntity.ok(eventResource);
}
modelMapper를 통해 dto에서 event로 값을 넣고 repository를 이용해서 save 메서드를 사용했는데,
jpa에서 엔티티 수정하는 과정에서 변경감지를 이용하기 때문에 update 메서드를 따로 안쓰고 그냥 해당 엔티티의 데이터가 수정되면 변경이 되는 것으로 알고있는데 아닌가요?
수정된 이벤트를 repository save로 명시적으로 DB에 저장해줘야한다.
트랜젝션 내에서 변경사항이 자동으로 더치체킹이돼서 트랜젝션이 커밋될 때 데이터베이스에 반영되는 일이 벌어지지 않음 → 서비스를 만들어야 이루어진다.
(현재 서비스를 만들지 않았으므로 명시적으로 DB에 저장하는 코드를 작성)