Controller - 책 저장하기

jihan kong·2022년 9월 28일
0

JUnit5

목록 보기
20/25
post-thumbnail

본 시리즈는 메타 코딩님의 Junit 강의를 학습한 내용을 바탕으로 정리하였습니다.

저번 시간을 끝으로 Service 레이어단의 모든 코딩이 끝났다. Service layer도 정말 할 일이 많았다. 기본적인 책 등록, 조회, 수정, 삭제 뿐만 아니라 가짜 mock 환경을 통해 테스트 또한 구현했다. Stub 이라는 개념도 이 때 처음 알게 되었다. 특히 Map method의 특성을 이해하고 그에 맞게 코드를 리팩토링하는 작업을 통해 코드를 보다 효율적으로 작성하고 가독성있게 작성하는 방법 또한 배웠다.

이제 모든 준비는 끝났다. 실제로 Client와 통신하는 Controller layer를 구현해보자.


Controller 구현

전에 만들어두었던 BookApiController.java 에 다음과 같이 코딩하자.

BookApiController.java

package site.metacoding.junitproject.web;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;
import site.metacoding.junitproject.service.BookService;
import site.metacoding.junitproject.web.dto.BookSaveReqDto;

@RequiredArgsConstructor
@RestController
public class BookApiController {  // 컴포지션 = has 관계

    private final BookService bookService;	

    // 책등록
    // key=value&key=value
    // { "key": value, "key": value } (json 타입)
    @PostMapping("/api/v1/book")						 //  1.
    public ResponseEntity<?> saveBook(@RequestBody BookSaveReqDto bookSaveReqDto) {  
    													 //  2. 
        bookService.책등록하기(bookSaveReqDto);
        return new ResponseEntity<>(HttpStatus.CREATED); //  3.
    }

    // 책목록보기
    public ResponseEntity<?> getBookList() {
        return null;
    }

    // 책한건보기
    public ResponseEntity<?> getBookOne() {
        return null;
    }

    // 책삭제하기
    public ResponseEntity<?> deleteBook() {
        return null;
    }

    // 책수정하기
    public ResponseEntity<?> updateBook() {
        return null;
    }
    
}

<코드설명>

  • 우리는 먼저 책 등록하기를 구현할 것이기 때문에 다른 메서드는 모두 return null 처리를 통해 오류를 발생하지 않도록 만든다.
  1. 책 등록 REST api를 구현하기 위해 @PostMapping 어노테이션을 사용한다. 또한 Controller는 계속해서 버젼업을 진행할 것이기 때문에 ("/api/v1/book") 과 같은 주소를 작성한다.
  2. 관리의 편의성을 위해 return type을 ResponseEntity<?> 와 같이 Generic Type으로 한다. 또한 { "key": value, "key": value } 와 같이 클라이언트에서 전송한 json 요청 데이터를 자바 객체로 받기 위해 @RequestBody 를 선언한다.
  3. 책 등록이 완료되면 HTTP 상태코드인 HttpStatus.CREATED 를 통해 201 Created 신호를 체크한다.

모든 설정이 끝났으니 우리의 main application을 실행한 후, postman을 통해 Json 으로 Body를 요청해보자.

위와 같이 상태코드 201 Created 가 잘 뜬 것으로 보아 클라이언트의 요청을 서버가 정상적으로 처리했고 새로운 리소스가 생겼다는 것을 알 수 있다.

그러나 한 가지 간과한 사실이 있다. 우리는 현재 컨트롤러 레이어를 구현 중에 있다. 클라이언트는 서비스와 리포지토리, DB를 거치면서 201 상태코드 뿐만 아니라 실제 요청한 Body 에 대한 응답 데이터도 응답받을 수 있게끔 구현되어야 한다.

따라서 이를 구현하기 위해선 코드의 수정이 필요하다.

🛠️ 코드의 수정

어떻게 수정하면 좋을까? 일단 컨트롤러와 중추적으로 통신하는 서비스 레이어를 다시 한번 살펴보자.

BookService.java

위와 같이 책 등록은 결국 BookRespDto 를 가지고 이루어지기 때문에 이를 기반으로 코드를 수정해야 한다. 따라서 컨트롤러의 내용을 다음과 같이 수정하자.


BookApiController.java

    // 1. 책등록
    @PostMapping("/api/v1/book")
    public ResponseEntity<?> saveBook(@RequestBody BookSaveReqDto bookSaveReqDto) {
        BookRespDto bookRespDto = bookService.책등록하기(bookSaveReqDto);
        return new ResponseEntity<>(bookRespDto, HttpStatus.CREATED); 
    }

postman을 통해 다시 한번 전송해보면 201 코드가 잘 뜨는 것을 볼 수 있다.


I'm still hungry...

이렇게 구현은 모두 되었지만 아직 배가 고프다.. 우리가 지금까지 했던 것은 사실 MDN 웹 표준에 관한 것으로 공통적이고 일반화된 것들을 구현하기에는 좋지만 우리만의 어떤 통신 규약이 없는 상태이다. 즉, 프론트엔드와 백엔드가 통신할 때 우리만의 프로토콜을 만들었으면 좋겠다.

dto 디렉토리에 각각 request, response 폴더를 생성하고 BookSaveReqDtorequest 에, BookRespDtoresponse 에 이동시킨다.

CMRespDto

response 폴더에 CMRespDto.java 파일을 생성한다. CM이란 Common 의 축약어로 말 그대로 공통된 Response 데이터를 전송해주는 작업을 이 Dto 에서 수행할 것이다.

CMRespDto.java

package site.metacoding.junitproject.web.dto.response;

import lombok.Builder;
import lombok.Getter;

@Getter
public class CMRespDto<T> { // Generic 타입
    private Integer code; // 1 성공, -1 실패
    private String msg;   // 에러메시지, 성공에 대한 메시지
    private T body;       // body의 내용이 어떤 것이 들어올지 모르기 때문에 
    					  // Generic 타입으로 선언

    @Builder
    public CMRespDto(Integer code, String msg, T body) {
        this.code = code;
        this.msg = msg;
        this.body = body;
    }
}

CMRespDto 를 통해 클라이언트는 요청 메세지에 대한 성공, 실패 에러메세지를 응답받을 수 있게 되었다.

CMRespDto 를 반영해서 컨트롤러 레이어도 다시 수정하자.


BookApiController.java

    // 1. 책등록
    @PostMapping("/api/v1/book")
    public ResponseEntity<?> saveBook(@RequestBody BookSaveReqDto bookSaveReqDto) {
        BookRespDto bookRespDto = bookService.책등록하기(bookSaveReqDto);
        CMRespDto<?> cmRespDto = CMRespDto.builder().code(1).msg("글 저장 성공").body(bookRespDto).build();
        return new ResponseEntity<>(cmRespDto, HttpStatus.CREATED);
    }

우리는 글 저장에 성공했을 때(1), "글 저장 성공" 이라는 메세지를 띄우기로 했다.
어플리케이션을 실행하고 postman을 통해 다시 post 요청을 보내면...

위와 같이 title, author 의 값 뿐만 아니라 상세 메시지 또한 응답으로 보내줄 수가 있게 되었다.

profile
학습하며 도전하는 것을 즐기는 개발자

0개의 댓글