728x90
스프링 기반 REST API 개발
2. 이벤트 생성 API 개발
포스팅 참조 정보
GitHub
공부한 내용은 GitHub에 공부용 Organizations에 정리 하고 있습니다
해당 포스팅에 대한 내용의 GitHub 주소
실습 내용이나 자세한 소스코드는 GitHub에 있습니다
포스팅 내용은 간략하게 추린 핵심 내용만 포스팅되어 있습니다
https://github.com/freespringlecture/spring-rest-api-study/tree/chap02-04_input_restrict
해당 포스팅 참고 인프런 강의
https://www.inflearn.com/course/spring_rest-api/dashboard
실습 환경
- Java Version: Java 11
- SpringBoot Version: 2.1.2.RELEASE
4. Event 생성 API 구현: 입력값 제한하기
입력값 제한
입력하기로한 값들 이외에는 무시하는 방법
- id 또는 입력받은 데이터로 계산 해야 하는 값들은 입력을 받지 않아야 한다
- EventDto 적용
- 너무 많은 애노테이션으로 코드가 복잡하고 지저분해지므로 분리해서 작업
- 입력받는 DTO 별도로 복사해서 처리
- 받아올 객체가 EventDto이기 떄문에 id가 있던 free가 있던 무시
DTO -> 도메인 객체로 값 복사
기존 클래스를 DTO로 손쉽게 변환해주는 라이브러리
ModelMapper
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.2</version>
</dependency>
ModelMapper 빈 등록
입력값은 EventDto로 받았지만 계산되어야 되는 필드들은 없으므로 걸러서 받고 걸러진 값들을 대상으로 이벤트 객체를 생성해서 eventRepository에 저장을 함
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
통합 테스트로 전환
Mocking 테스트를 하려고 만든 객체와 새롭게 EventDto로 생성한 객체가 달라서 null
을 리턴해줘서 NullPointException이 일어남
@WebMvcTest
빼고 다음 애노테이션 추가@SpringBootTest
- 테스트할때는
@SpringBootTest
로 테스트하는게 편함 Mocking 해줘야 될게 너무많아서 관리가 힘듬 - 애플리케이션을 실행했을때와 가장 근사한 테스트를 만들어 작성할 수 있음
- 테스트할때는
@AutoConfigureMockMvc
- MockMvc를 계속 사용하기 위해 적용
- Repository
@MockBean
코드 제거
테스트 할 것
- 입력값으로 누가 id나 eventStatus, offline, free 이런 데이터까지 같이 주면?
- Bad_Request로 응답 vs 받기로 한 값 이외는 무시
입력값 제한하기 로직 작성
1. EvnetDto 추가
package me.freelife.rest.events;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class EventDto {
private String name; //이벤트 네임
private String description; // 설명
private LocalDateTime beginEnrollmentDateTime; //등록 시작일시
private LocalDateTime closeEnrollmentDateTime; //종료일시 private LocalDateTime beginEventDateTime; //이벤트 시작일시
private LocalDateTime beginEventDateTime; //이벤트 시작일시
private LocalDateTime endEventDateTime; //이벤트 종료일시
private String location; // (optional) 이벤트 위치 이게 없으면 온라인 모임
private int basePrice; // (optional) 기본 금액
private int maxPrice; // (optional) 최고 금액
private int limitOfEnrollment; //등록한도
}
2. Event 도메인에 eventStatus 기본값 DRAFT로 지정
...
public class Event {
...
@Enumerated(EnumType.STRING)
private EventStatus eventStatus = EventStatus.DRAFT; // 이벤트 상태
}
3. EventController에 modelMapper 사용
...
public class EventController {
private final EventRepository eventRepository;
private final ModelMapper modelMapper;
public EventController(EventRepository eventRepository, ModelMapper modelMapper) {
this.eventRepository = eventRepository;
this.modelMapper = modelMapper;
}
@PostMapping
public ResponseEntity createEvent(@RequestBody EventDto eventDto) {
//EventDto에 있는 것을 Event 타입의 인스턴스로 만들어 달라
Event event = modelMapper.map(eventDto, Event.class);
Event newEvent = this.eventRepository.save(event);
//EventController의 id에 해당하는 링크를 만들고 링크를 URI로 변환
//API에 events에 어떤 특정한 ID 그 ID가 생성된 이벤트에 Location Header에 들어감
URI createdUri = linkTo(EventController.class).slash(newEvent.getId()).toUri();
event.setId(10);
// createdUri 헤더를 가지고 201응답을 만듬
return ResponseEntity.created(createdUri).body(event);
}
}
4. Event 생성 API 테스트 코드 수정
- 테스트를
@WebMvcTest
에서@SpringBootTest
로 변경하고@AutoConfigureMockMvc
추가 - MockMvc 의존성 주입
- id, free, offLine, eventStatus 테스트 데이터 추가 및 검증 로직 추가
package me.freelife.rest.events;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import java.time.LocalDateTime;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class EventControllerTests {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@Test
public void createEvent() throws Exception {
Event event = Event.builder()
.id(100)
.name("Spring")
.description("REST API Development with Spring")
.beginEnrollmentDateTime(LocalDateTime.of(2018, 11, 23, 14, 21))
.closeEnrollmentDateTime(LocalDateTime.of(2018, 11, 24, 14, 21))
.beginEventDateTime(LocalDateTime.of(2018, 11, 25, 14, 21))
.endEventDateTime(LocalDateTime.of(2018, 11, 26, 14, 21))
.basePrice(100)
.maxPrice(200)
.limitOfEnrollment(100)
.location("강남역 D2 스타텁 팩토리")
.free(true)
.offline(false)
.eventStatus(EventStatus.PUBLISHED)
.build();
mockMvc.perform(post("/api/events/")
.contentType(MediaType.APPLICATION_JSON_UTF8) //요청타입
.accept(MediaTypes.HAL_JSON) //받고싶은 타입
.content(objectMapper.writeValueAsString(event))) //event를 json을 String으로 맵핑
.andDo(print())
.andExpect(status().isCreated()) // 201 상태인지 확인
.andExpect(jsonPath("id").exists()) //ID가 있는지 확인
.andExpect(header().exists(HttpHeaders.LOCATION)) // HEADER에 Location 있는지 확인
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_UTF8_VALUE)) //Content-Type 값 확인
.andExpect(jsonPath("id").value(Matchers.not(100))) // ID가 100이 아니면
.andExpect(jsonPath("free").value(Matchers.not(true))) // free가 true가
.andExpect(jsonPath("eventStatus").value(EventStatus.DRAFT.name()))
;
}
}
728x90
'개발강의정리 > Spring' 카테고리의 다른 글
[스프링 기반 REST API 개발] 2-6. Event 생성 API 구현: Bad Request 처리하기 (0) | 2019.12.28 |
---|---|
[스프링 기반 REST API 개발] 2-5. Event 생성 API 구현: 입력값 이외에 에러 발생 (0) | 2019.12.28 |
[스프링 기반 REST API 개발] 2-3. Event 생성 API 구현: EventRepository 구현 (0) | 2019.12.28 |
[스프링 기반 REST API 개발] 2-2. Event 생성 API 구현: 201 응답 받기 (0) | 2019.12.28 |
[스프링 기반 REST API 개발] 2-1. Event 생성 API 구현: 테스트 만들자 (0) | 2019.12.28 |
댓글