등록/수정/조회 API

iseon_u·2023년 3월 22일
0

Book

목록 보기
5/16
post-thumbnail

CH03 - 등록/수정/조회 API


API를 위한 3개의 클래스

  • Request 데이터를 받을 Dto
  • API 요청을 받을 Controller
  • 트랜잭션, 도메인 기능 간의 순서를 보장하는 Service

Service 는 트랜잭션, 도메인 간 순서 보장 역할

  • Web Layer
    • 컨트롤러와 JSP/Freemarker 같은 뷰 템플릿 영역
    • 필터, 인터셉터, 컨트롤러 어드바이스 등 외부 요청과 응답의 영역
  • Service Layer
    • @Service 에 사용되는 서비스 영역
    • 일반적으로 Controller와 Dao 의 중간 영역에서 사용
    • @Transactional 이 사용되어야 하는 영역
    • 트랜잭션과 도메인 간의 순서만 보장
    • 트랜잭션 스크립트
      • 서비스로 비지니스 처리하는 방식
      • 서비스 계층이 무의미
  • Repository Layer
    • Database 와 같이 데이터 저장소에 접근하는 영역
    • Dao 영역
  • Dtos
    • Dto 는 계층 간에 데이터 교환을 위한 객체
  • Domain Model
    • 도메인이라 불리는 개발 대상을 동일한 관점에서 단순화시킨 것
    • 비지니스 처리 담당

스프링에서 Bean 을 주입받는 방식

  • @Autowired, setter, 생성자
  • 생성자로 주입받는 방식을 가장 권장
  • @RequiredArgsConstructor
    • final 선언된 필드를 인자 값으로 하는 생성자를 생성
    • 컨트롤러에 새로운 서비스를 추가하거나 기존 컴포넌트를 제거해도 생성자 코드는 자동으로 변경

등록 DTO 클래스

PostsSaveRequestDto.java

@Getter
@NoArgsConstructor
public class PostsSaveRequestDto {
    private String title;
    private String content;
    private String author;

    @Builder
    public PostsSaveRequestDto(String title, String content, String author) {
        this.title = title;
        this.content = content;
        this.author = author;
    }

    public Posts toEntity() {
        return Posts.builder()
                .title(title)
                .content(content)
                .author(author)
                .build();
    }
}
  • Entity 클래스와 유사하지만 Dto 클래스를 따로 생성
    • Entity 클래스를 Request/Response 클래스로 사용하면 안된다
  • Entity 클래스는 데이터베이스와 맞닿은 핵심 클래스
  • Request/Response Dto 는 View 를 위한 클래스
    • 변경이 잦다
  • 여러 테이블을 조인해서 줘야 할 경우 Entity 클래스만으로 표현하기 어렵다

등록 테스트 코드

PostsApiControllerTest.java

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PostsApiControllerTest {

    @LocalServerPort
    private int port;

    @Autowired
    private PostsRepository postsRepository;

    @Autowired
    private WebApplicationContext context;

    private MockMvc mvc;

    @Before
    public void setup() {
        mvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(springSecurity())
                .build();
    }

    @After
    public void tearDown() throws Exception {
        postsRepository.deleteAll();
    }

    @Test
    @WithMockUser(roles="USER")
    public void Posts_등록된다() throws Exception {
        //given
        String title = "title";
        String content = "content";
        PostsSaveRequestDto requestDto = PostsSaveRequestDto.builder()
                .title(title)
                .content(content)
                .author("author")
                .build();

        String url = "http://localhost:" + port + "/api/v1/posts";

        //when
        mvc.perform(post(url)
                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                        .content(new ObjectMapper().writeValueAsString(requestDto)))
                .andExpect(status().isOk());

        //then
        List<Posts> all = postsRepository.findAll();
        assertThat(all.get(0).getTitle()).isEqualTo(title);
        assertThat(all.get(0).getContent()).isEqualTo(content);
    }
}
  • WebEnvironment.RANDOM_PORT
    • 랜덤 포트 실행

조회 DTO 클래스

PostResponseDto.java

public class PostsResponseDto {

    private Long id;
    private String title;
    private String content;
    private String author;

    public PostsResponseDto(Posts entity) {
        this.id = entity.getId();
        this.title = entity.getTitle();
        this.content = entity.getContent();
        this.author = entity.getAuthor();
    }
}
  • PostResponseDto 는 Entity 의 필드 중 일부만 사용
    • 모든 필드를 가진 생성자가 필요하지 않기 때문에 생성자로 Entity 를 받아 필드에 값을 넣는다
profile
🧑🏻‍💻 Hello World!

0개의 댓글