-
이벤트 생성 API 개발 - 1백기선(인프런 강의)/스프링 기반 REST API 개발 2021. 1. 22. 19:19반응형
위 GIT주소에 개발 step 별로 commit 해두었다.
진행되는 과정은 아래와 같다.
1. 입력값들을 전달하면 JSON 응답으로 201이 나오는지 확인.
- Location 헤더에 생성된 이벤트를 조회할 수 있는 URI 담겨 있는지 확인.
- id는 자동생성된 값으로 나오는지 확인
2. 입력값으로 누가 id나 eventStatus, offline, free 이런 데이터까지 같이 주면?
- Bad_Request로 응답 vs 받기로 한 값 이외는 무시
3. 입력 데이터가 이상한 경우 Bad_Request로 응답
- 입력값이 이상한 경우 에러
- 비즈니스 로직으로 검사할 수 있는 에러
- 에러 응답 메시지에 에러에 대한 정보가 있어야 한다.
4. 비즈니스 로직 적용 됐는지 응답 메시지 확인
- offline과 free 값 확인
5. 응답에 HATEOA와 profile 관련 링크가 있는지 확인.
- self (view)
- update (만든 사람은 수정할 수 있으니까)
- events (목록으로 가는 링크)
6. API 문서 만들기
- 요청 문서화
- 응답 문서화
- 링크 문서화
- profile 링크 추가
1. 입력값들을 전달하면 JSON 응답으로 201이 나오는지 확인.
1-1. Event 생성 API 구현: 201 응답 받기
@RestController
- @ResponseBody를 모든 메소드에 적용한 것과 동일하다.
ResponseEntity를 사용하는 이유
- 응답 코드, 헤더, 본문 모두 다루기 편한 API
Location URI 만들기
- HATEOS가 제공하는 linkTo(), methodOn() 사용
객체를 JSON으로 변환
- ObjectMapper 사용
1-2. Event 생성 API 구현: EventRepository 구현
스프링 데이터 JPA
- JpaRepository 상속 받아 만들기
Enum을 JPA 맵핑시 주의할 것
- @Enumerated(EnumType.STRING)
@MockBean
- Mockito를 사용해서 mock 객체를 만들고 빈으로 등록해 줌.
- (주의) 기존 빈을 테스트용 빈이 대체 한다.
2. 입력값으로 누가 id나 eventStatus, offline, free 이런 데이터까지 같이 주면?
2-1. Event 생성 API 구현: 입력값 제한하기
입력값 제한
- id 또는 입력 받은 데이터로 계산해야 하는 값들은 입력을 받지 않아야 한다.
- EventDto 적용
- 도메인 객체로 값 복사
통합 테스트로 전환
- @WebMvcTest 빼고 다음 애노테이션 추가
- @SpringBootTest
- @AutoConfigureMockMvc
- Repository @MockBean 코드 제거
전환이유 -> 아래와같이 Controller에서 Event event로 받을 경우에는 WebMvcTest가 가능했지만 EventDto로 변경하면서 들어오는 객체가 달라졌기 때문에
@PostMapping public ResponseEntity createEvnet(@RequestBody Event event) { Event newEvent = this.eventRepository.save(event); URI createUri = linkTo(EventController.class).slash(newEvent.getId()).toUri(); return ResponseEntity.created(createUri).body(event); }
3. 입력 데이터가 이상한 경우 Bad_Request로 응답
3-1. Event 생성 API 구현: 입력값 이외에 에러 발생
ObjectMapper 커스터마이징
application.properties에 아래와같이 추가
spring.jackson.deserialization.fail-on-unknown-properties=true
3-2. Event 생성 API 구현: Bad Request 처리하기
@Valid와 BindingResult (또는 Errors)
- @Valid는 Request에 들어있는 값들을 바인딩 해줄때 사용
- BindingResult는 항상 @Valid 바로 다음 인자로 사용해야 함. (스프링 MVC)
- @NotNull, @NotEmpty, @Min, @Max, ... 사용해서 입력값 바인딩할 때 에러 확인할 수 있음
- 만약 최신버전을 사용하게 되다면 @Valid가 작동이 되지 않는다.
- 스프링부트 버전 2.3.0부터는 starter web에 디펜던시로 spring-boot-starter-validation이 제외되서, 별도로 추가 해야 함
- www.youtube.com/watch?v=cP8TwMV4LjE
도메인 Validator 만들기
- Validator 인터페이스 없이 만들어도 상관없음
3-3. Event 생성 API 구현: Bad Request 응답 본문 만들기
커스텀 JSON Serializer 만들기
- extends JsonSerializer<T> (Jackson JSON 제공)
- @JsonComponent (스프링 부트 제공)
Event는 ResponseEntity body안에 넣어도 가능하지만 errors는 아래와같이 못넣는 이유
java Bean 스펙을 따르기 때문에 modelMapper가 BeanSerializer를 이용해서 json을 만들어 주지만 errors는 java Bean 스펙을 따르지 않아서 사용하지 못한다.
@PostMapping public ResponseEntity createEvent(@RequestBody @Valid EventDto eventDto, Errors errors) { if(errors.hasErrors()){ //return ResponseEntity.badRequest().build(); return ResponseEntity.badRequest().body(errors); } eventValidator.validate(eventDto, errors); if(errors.hasErrors()){ //return ResponseEntity.badRequest().build(); return ResponseEntity.badRequest().body(errors); } Event event = modelMapper.map(eventDto, Event.class); Event newEvent = this.eventRepository.save(event); URI createUri = linkTo(EventController.class).slash(newEvent.getId()).toUri(); return ResponseEntity.created(createUri).body(event); }
BindingError
- FieldError 와 GlobalError (ObjectError)가 있음
- objectName
- defaultMessage
- code
- field
- rejectedValue
4. 비즈니스 로직 적용 됐는지 응답 메시지 확인
4-1. Event 생성 API 구현: 비즈니스 로직 적용
4-2. Event 생성 API 구현: 매개변수를 이용한 테스트
@ParameterizedTest(name = "{index} => basePrice={0}, maxPrice={1}, isFree={2}") @CsvSource({ "0, 0, true", "100, 0, falae", "0, 1000, falae" }) public void updateFree(int basePrice, int maxPrice, boolean isFree){ // Given Event event = Event.builder() .basePrice(basePrice) .maxPrice(maxPrice) .build(); //When event.update(); // Then assertThat(event.isFree()).isEqualTo(isFree); } // Junit 5 기준 @ParameterizedTest(name = "{index} => location={0}, isOffline={1}") @MethodSource("updateOfflineParam") public void updateOffline(String location, boolean isOffline){ System.out.println("테스트요 : " + location + " / " + isOffline); // Given Event event = Event.builder() .location(location) .build(); //When event.update(); // Then assertThat(event.isOffline()).isEqualTo(isOffline); } // static 있어야 동작 private static Object[] updateOfflineParam() { return new Object[]{ new Object[]{null, true}, new Object[]{"", true}, new Object[]{"경기도 안양시 만안구", false} }; }
Json Serializer와 Json deSerializer란?
Json Serializer
객체를 JSon으로 변경
Json Deserialzer
Json객체를 객체로 변경
테스트 내용
1) 입력값들을 전달하면 JSON 응답으로 201이 나오는지 확인.
- Location 헤더에 생성된 이벤트를 조회할 수 있는 URI 담겨 있는지 확인.
- id는 DB에 들어갈 때 자동생성된 값으로 나오는지 확인
2) 입력값으로 누가 id나 eventStatus, offline, free 이런 데이터까지 같이 주면?
- Bad_Request로 응답 vs 받기로 한 값 이외는 무시
3) 입력 데이터가 이상한 경우 Bad_Request로 응답
- 입력값이 이상한 경우 에러
- 비즈니스 로직으로 검사할 수 있는 에러
- 에러 응답 메시지에 에러에 대한 정보가 있어야 한다
4) 비즈니스 로직 적용 됐는지 응답 메시지 확인
- offline과 free 값 확인
반응형'백기선(인프런 강의) > 스프링 기반 REST API 개발' 카테고리의 다른 글
REST API 보안 적용 (0) 2021.01.24 이벤트 생성 API 개발 -3 (0) 2021.01.24 이벤트 생성 API 개발 -2 (0) 2021.01.23 스프링 HATEOAS (0) 2021.01.23 REST API 소개 (0) 2021.01.21