개발강의정리/Spring

[스프링 기반 REST API 개발] 2-3. Event 생성 API 구현: EventRepository 구현

nineDeveloper 2019. 12. 28.
728x90

스프링 기반 REST API 개발

2. 이벤트 생성 API 개발

포스팅 참조 정보

GitHub

공부한 내용은 GitHub에 공부용 Organizations에 정리 하고 있습니다

해당 포스팅에 대한 내용의 GitHub 주소

실습 내용이나 자세한 소스코드는 GitHub에 있습니다
포스팅 내용은 간략하게 추린 핵심 내용만 포스팅되어 있습니다

https://github.com/freespringlecture/spring-rest-api-study/tree/chap02-03_event_repo

해당 포스팅 참고 인프런 강의

https://www.inflearn.com/course/spring_rest-api/dashboard

실습 환경

  • Java Version: Java 11
  • SpringBoot Version: 2.1.2.RELEASE

3. Event 생성 API 구현: EventRepository 구현

스프링 데이터 JPA

JpaRepository 상속 받아 만들기

Enum을 JPA 맵핑시 주의할 것

@Enumerated(EnumType.STRING)

@MockBean

  • Mockito를 사용해서 mock 객체를 만들고 빈으로 등록해 줌
  • (주의) 기존 빈을 테스트용 빈이 대체 한다

    테스트 할 것

  • 입력값들을 전달하면 JSON 응답으로 201이 나오는지 확인
    • Location 헤더에 생성된 이벤트를 조회할 수 있는 URI 담겨 있는지 확인
    • idDB에 들어갈 때 자동생성된 값으로 나오는지 확인

EventRepository 구현

1. EventRepository 코드 작성

package me.freelife.rest.events;

import org.springframework.data.jpa.repository.JpaRepository;

public interface EventRepository extends JpaRepository<Event, Integer> {
}

2. Event 도메인 클래스에 JPA 어노테이션 추가


...

import javax.persistence.*;

...

@Entity
public class Event {

    @Id @GeneratedValue
    private Integer id; // 추가 식별자

    ...

    @Enumerated(EnumType.STRING)
    private EventStatus eventStatus; // 이벤트 상태
}

3. EventController 에서 EventRepository 사용

package me.freelife.rest.events;

import org.springframework.hateoas.MediaTypes;
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;

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;

    public EventController(EventRepository eventRepository) {
        this.eventRepository = eventRepository;
    }

    @PostMapping
    public ResponseEntity createEvent(@RequestBody Event event) {
        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 테스트 코드 EventRepository 사용하도록 수정

package me.freelife.rest.events;

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.WebMvcTest;
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)
@WebMvcTest
public class EventControllerTests {

    @Autowired
    MockMvc mockMvc;

    @Autowired
    ObjectMapper objectMapper;

    // 슬라이싱 테스트라 Repository가 빈으로 등록되지 않아 MockBean을 지정
    // Mock 이라서 save 하는 값들이 전부 null
    @MockBean
    EventRepository eventRepository;

    @Test
    public void createEvent() throws Exception {
        Event event = Event.builder()
                .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 스타텁 팩토리")
                .build();
        //이벤트 ID 10으로 임의 설정
        event.setId(10);
        //eventRepository에 save가 호출되면 event를 리턴하라
        Mockito.when(eventRepository.save(event)).thenReturn(event);

        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 값 확인
    }

}
728x90

댓글

💲 추천 글