[Spring REST API #3] Spring REST API 입력값 제한 및 에러 발생 처리
- 📚 Spring/Spring REST
- 2020. 7. 27. 00:05
REST API를 설계할 시 Client 측에서 잘못된 데이터를 요청하거나 전송할 시 그것을 처리하는 로직을 만들어야 합니다. 여기서는 DTO(Data Transfer Object)와 스프링 부트에서 제공하는 설정 정보를 이용해 손쉽게 해당 로직을 적용할 것입니다.
package org.kyhslam.rest;
import org.modelmapper.ModelMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class RestApplication {
public static void main(String[] args) {
SpringApplication.run(RestApplication.class, args);
}
@Bean
public ModelMapper modelMapper(){
return new ModelMapper();
}
}
ModelMapper Bean으로 등록
package org.kyhslam.rest;
import lombok.*;
import javax.persistence.*;
import java.time.LocalDateTime;
@Builder @AllArgsConstructor @NoArgsConstructor
@Setter @Getter @EqualsAndHashCode(of = "id")
@Entity
public class Event {
@Id @GeneratedValue
private Integer id;
private String name;
private String description;
private LocalDateTime beginEnrollmentDateTime;
private LocalDateTime closeEnrollmentDateTime;
private LocalDateTime beginEventDateTime;
private LocalDateTime endEventDateTime;
private String location; // (optional)
private int basePrice; // (optional)
private int maxPrice; // (optional)
private int limitOfEnrollment;
private boolean offline;
private boolean free;
@Enumerated(EnumType.STRING)
private EventStatus eventStatus = EventStatus.DRAFT;
}
EventDTO
package org.kyhslam.rest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Builder @NoArgsConstructor @AllArgsConstructor
@Data
public class EventDto {
private String name;
private String description;
private LocalDateTime beginEnrollmentDateTime;
private LocalDateTime closeEnrollmentDateTime;
private LocalDateTime beginEventDateTime;
private LocalDateTime endEventDateTime;
private String location; // (optional)
private int basePrice; // (optional)
private int maxPrice; // (optional)
private int limitOfEnrollment;
}
package org.kyhslam.rest;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.mvc.ControllerLinkBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import java.net.URI;
@Controller
@RequestMapping(value = "/api/events", produces = MediaTypes.HAL_JSON_UTF8_VALUE)
public class EventController {
@Autowired
EventRepository eventRepository;
@Autowired
ModelMapper modelMapper;
@PostMapping
public ResponseEntity createEvent(@RequestBody EventDto eventDto){
Event event = modelMapper.map(eventDto, Event.class); // Dto를 event로 변환
Event newEvent = eventRepository.save(event);
URI createdUri = ControllerLinkBuilder.linkTo(EventController.class).slash(newEvent.getId()).toUri();
return ResponseEntity.created(createdUri).body(event);
}
}
테스트
package org.kyhslam.rest;
import com.fasterxml.jackson.databind.ObjectMapper;
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 org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import java.time.LocalDateTime;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class EventControllerTests {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@Test
public void createEvent() throws Exception {
Event event = Event.builder()
.name("Spring")
.description("REST API Development")
.beginEnrollmentDateTime(LocalDateTime.of(2018,11,23,14,21))
.closeEnrollmentDateTime(LocalDateTime.of(2018,11,23,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 팩토리")
.build();
mockMvc.perform(MockMvcRequestBuilders.post("/api/events/")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON)
.content(objectMapper.writeValueAsString(event)))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isCreated())
.andExpect(MockMvcResultMatchers.jsonPath("id").exists())
.andExpect(MockMvcResultMatchers.header().exists(HttpHeaders.LOCATION))
.andExpect(MockMvcResultMatchers.header().string(HttpHeaders.CONTENT_TYPE,MediaTypes.HAL_JSON_UTF8_VALUE));
}
}
결과
MockHttpServletRequest:
HTTP Method = POST
Request URI = /api/events/
Parameters = {}
Headers = {Content-Type=[application/json;charset=UTF-8], Accept=[application/hal+json]}
Body = {"id":null,"name":"Spring","description":"REST API Development","beginEnrollmentDateTime":"2018-11-23T14:21:00","closeEnrollmentDateTime":"2018-11-23T14:21:00","beginEventDateTime":"2018-11-25T14:21:00","endEventDateTime":"2018-11-26T14:21:00","location":"강남역 d2 팩토리","basePrice":100,"maxPrice":200,"limitOfEnrollment":100,"offline":false,"free":false,"eventStatus":null}
Session Attrs = {}
Handler:
Type = org.kyhslam.rest.EventController
Method = public org.springframework.http.ResponseEntity org.kyhslam.rest.EventController.createEvent(org.kyhslam.rest.EventDto)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 201
Error message = null
Headers = {Location=[http://localhost/api/events/1], Content-Type=[application/hal+json;charset=UTF-8]}
Content type = application/hal+json;charset=UTF-8
Body = {"id":1,"name":"Spring","description":"REST API Development","beginEnrollmentDateTime":"2018-11-23T14:21:00","closeEnrollmentDateTime":"2018-11-23T14:21:00","beginEventDateTime":"2018-11-25T14:21:00","endEventDateTime":"2018-11-26T14:21:00","location":"강남역 d2 팩토리","basePrice":100,"maxPrice":200,"limitOfEnrollment":100,"offline":false,"free":false,"eventStatus":"DRAFT"}
Forwarded URL = null
Redirected URL = http://localhost/api/events/1
Cookies = []
'📚 Spring > Spring REST' 카테고리의 다른 글
[Spring REST API #6] Bad Request (도메인 Validator를 통한 처리) (0) | 2020.07.31 |
---|---|
[Spring REST API #5] Bad Request 처리 (0) | 2020.07.30 |
[Spring REST API #4] Spring REST API Bad Request 처리 (0) | 2020.07.28 |
[Spring REST API #2] Spring REST API 클래스 생성 및 201 테스트 (0) | 2020.07.19 |
REST API 란? (0) | 2020.06.20 |