728x90
스프링 기반 REST API 개발
2. 이벤트 생성 API 개발
포스팅 참조 정보
GitHub
공부한 내용은 GitHub에 공부용 Organizations에 정리 하고 있습니다
해당 포스팅에 대한 내용의 GitHub 주소
실습 내용이나 자세한 소스코드는 GitHub에 있습니다
포스팅 내용은 간략하게 추린 핵심 내용만 포스팅되어 있습니다
https://github.com/freespringlecture/spring-rest-api-study/tree/chap02-06_bad_request_handle
해당 포스팅 참고 인프런 강의
https://www.inflearn.com/course/spring_rest-api/dashboard
실습 환경
- Java Version: Java 11
- SpringBoot Version: 2.1.2.RELEASE
6. Event 생성 API 구현: Bad Request 처리하기
입력값이 이상한 경우에 Bad Request를 보내는 방법
@Valid
와 BindingResult (또는 Errors)
스프링 MVC에 해당하는 내용 JS303 애노테이션을 사용해 확인할 수 있음
@Valid
라는 애노테이션을 붙이면 Entity에 바인딩을 할때 애노테이션들에 대한 정보를 참고해서 검증을 수행함- 검증을 수행한 결과를 객체 오른쪽에 있는 Errors 객체에 에러값들을 넣어줌
- 받은 에러를 확인 해서 Bad Request를 발생시킴
BindingResult는 항상
@Valid
바로 다음 인자로 사용해야 함 (스프링 MVC)@NotNull
,@NotEmpty
,@Min
,@Max
, ... 사용해서 입력값 바인딩할 때 에러 확인할 수 있음
도메인 Validator 만들기
Validator 인터페이스 없이 만들어도 상관없음
Junit5로 테스트하면 테스트 설명이 나옴
테스트 설명 용 애노테이션 만들기
@Target
, @Retention
common 패키지를 생성하고 TestDescription 설명 용 어노테이션 생성
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface TestDescription {
String value();
}
테스트 할 것
- 입력 데이터가 이상한 경우 Bad_Request로 응답
- 입력값이 이상한 경우 에러
- 비즈니스 로직으로 검사할 수 있는 에러
- 에러 응답 메시지에 에러에 대한 정보가 있어야 한다
Bad Request 처리 로직 작성
1. EventDto에 validation 어노테이션 추가
package me.freelife.rest.events;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class EventDto {
@NotEmpty
private String name; //이벤트 네임
@NotEmpty
private String description; // 설명
@NotNull
private LocalDateTime beginEnrollmentDateTime; //등록 시작일시
@NotNull
private LocalDateTime closeEnrollmentDateTime; //종료일시 private LocalDateTime beginEventDateTime; //이벤트 시작일시
@NotNull
private LocalDateTime beginEventDateTime; //이벤트 시작일시
@NotNull
private LocalDateTime endEventDateTime; //이벤트 종료일시
private String location; // (optional) 이벤트 위치 이게 없으면 온라인 모임
@Min(0)
private int basePrice; // (optional) 기본 금액
@Min(0)
private int maxPrice; // (optional) 최고 금액
@Min(0)
private int limitOfEnrollment; //등록한도
}
2. EventValidator 추가
package me.freelife.rest.events;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import java.time.LocalDateTime;
@Component
public class EventValidator {
public void validate(EventDto eventDto, Errors errors) {
String wrongValue = "wrongValue";
if(eventDto.getBasePrice() > eventDto.getMaxPrice() && eventDto.getMaxPrice() > 0) {
errors.rejectValue("basePrice", wrongValue, "BasePrice is wrong");
errors.rejectValue("maxPrice", wrongValue, "MaxPrice is wrong");
}
LocalDateTime endEventDateTime = eventDto.getEndEventDateTime();
if(endEventDateTime.isBefore(eventDto.getBeginEventDateTime()) ||
endEventDateTime.isBefore(eventDto.getCloseEnrollmentDateTime()) ||
endEventDateTime.isBefore(eventDto.getBeginEnrollmentDateTime())) {
errors.rejectValue("endEventDateTime", wrongValue, "endEventDateTime is wrong");
}
// TODO beginEventDateTime
// TODO CloseEnrollmentDateTime
}
}
3. Event 생성 API에 validation 처리 로직 추가
package me.freelife.rest.events;
import org.modelmapper.ModelMapper;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
import java.net.URI;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
@Controller
@RequestMapping(value = "/api/events", produces = MediaTypes.HAL_JSON_UTF8_VALUE)
public class EventController {
private final EventRepository eventRepository;
private final ModelMapper modelMapper;
private final EventValidator eventValidator;
public EventController(EventRepository eventRepository, ModelMapper modelMapper, EventValidator eventValidator) {
...
this.eventValidator = eventValidator;
}
@PostMapping
public ResponseEntity createEvent(@RequestBody @Valid EventDto eventDto, Errors errors) {
if(errors.hasErrors())
return ResponseEntity.badRequest().build();
eventValidator.validate(eventDto, errors);
if(errors.hasErrors()) {
return ResponseEntity.badRequest().build();
}
...
}
}
4. Event 생성 API 테스트 코드에 @TestDescription
적용 및 Bad Request 응답 테스트 코드 추가
...
import me.freelife.rest.common.TestDescription;
...
public class EventControllerTests {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@Test
@TestDescription("정상적으로 이벤트를 생성하는 테스트")
public void createEvent() throws Exception {
...
}
@Test
@TestDescription("입력 받을 수 없는 값을 사용한 경우에 에러가 발생하는 테스트")
public void createEvent_Bad_Request() throws Exception {
...
}
@Test
@TestDescription("입력 값이 비어있는 경우에 에러가 발생하는 테스트")
public void createEvent_Bad_Request_Empty_Input() throws Exception {
...
}
@Test
@TestDescription("입력 값이 잘못된 경우에 에러가 발생하는 테스트")
public void createEvent_Bad_Request_Wrong_Input() throws Exception {
EventDto eventDto = EventDto.builder()
.name("Spring")
.description("REST API Development with Spring")
.beginEnrollmentDateTime(LocalDateTime.of(2018, 11, 26, 14, 21))
.closeEnrollmentDateTime(LocalDateTime.of(2018, 11, 25, 14, 21))
.beginEventDateTime(LocalDateTime.of(2018, 11, 24, 14, 21))
.endEventDateTime(LocalDateTime.of(2018, 11, 23, 14, 21))
.basePrice(10000)
.maxPrice(200)
.limitOfEnrollment(100)
.location("강남역 D2 스타텁 팩토리")
.build();
this.mockMvc.perform(post("/api/events")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(this.objectMapper.writeValueAsString(eventDto)))
.andExpect(status().isBadRequest())
;
}
}
728x90
'개발강의정리 > Spring' 카테고리의 다른 글
[스프링 기반 REST API 개발] 2-8. Event 생성 API 구현: 비즈니스 로직 적용 (0) | 2019.12.28 |
---|---|
[스프링 기반 REST API 개발] 2-7. Event 생성 API 구현: Bad Request 응답 본문 만들기 (0) | 2019.12.28 |
[스프링 기반 REST API 개발] 2-5. Event 생성 API 구현: 입력값 이외에 에러 발생 (0) | 2019.12.28 |
[스프링 기반 REST API 개발] 2-4. Event 생성 API 구현: 입력값 제한하기 (0) | 2019.12.28 |
[스프링 기반 REST API 개발] 2-3. Event 생성 API 구현: EventRepository 구현 (0) | 2019.12.28 |
댓글