[스프링 부트 공부 일지] 3. 스프링에서 REST API 개발하기 (1)

2022. 12. 16. 17:04·공부/Spring Boot

HTTP 메서드 GET, DELETE, POST, PUT을 스프링에서 REST-API 방식으로 처리하는 방법을 알아본다.

GET, DELETE 메서드

- 두 메서드는 HTTP 요청 메세지에 바디가 없다.

- 그러므로 서버에 데이터를 전달 할 때는, URI에 포함하거나 파라미터를 사용하거나 헤더에 포함하여 전송한다.

 

1. 호텔 정보 조회 API 명세서

- 기본적으로는 호텔 객실 정보를 조회하는 API 이다.

- 단순 리소스 조회이므로 GET 메서드를 사용하며, 호텔을 구부할 수있는 고유 아이디 {hotelId}와 객실을 구분하는 {roomNumber}를 사용한다.

- 하지만 요청을 보낼 때, 예약 시작일(fromDate)와 예약 종료일(toDate)를 같이 보내면 예약 정보를 포함하여 응답한다. 포함하지 않으면  응답하지 않는다.

# REST-API 요청
GET /hotels/{hotelId}/rooms/{roomNumber}?fromDate={yyyyMMdd}&toDtate={yyyyMMdd}

# REST-API 응답
{
  "id" : 1201928183,
  "roomNumber" : "West-Wing-3928",
  "numberOfBeds" : 2,
  "roomType" : "deluxe",
  "originalPrice" : 150.00,
  
  # 예약일을 지정했을 때 포함되는 응답
  "reservations" : [
    {
      "id" : 129171201928183,
      "reservedDate" : "yyyy-MM-dd"
    },
    {
      "id" : 129171201928183,
      "reservedDate" : "yyyy-MM-dd"
    }
  ]
}

 

- 기본적으로 위와 같이 방 정보를 응답하며, 예약일을 지정해서 보내면 고유 예약 아이디와 함께 예약일을 리스트 형태로 응답하여 준다.

 

2. Controller 구현

- 명세서를 설계하였으면, 그에 맞게 API를 구현해야한다. 먼저 요청을 제일 먼저 받는 Controller부터 작성한다.

@RestController
public class HotelRoomController {

    @GetMapping("/hotels/{hotelId}/rooms/{roomNumber}")
    public HotelRoomResponse getHotelRoomByPerios(@PathVariable Long hotelId, @PathVariable String roomNumber,
                                                  @RequestParam(value = "fromDate", required = false) @DateTimeFormat(pattern = "yyyyMMdd") LocalDate fromDate,
                                                  @RequestParam(value = "toDate", required = false) @DateTimeFormat(pattern = "yyyyMMdd") LocalDate toDate) {

        Long hotelRoomId = IdGenerator.create(); // 랜덤한 hotelRoomIdfmf 생성한다.
        BigDecimal originalPrice = new BigDecimal("130.00"); // 가격을 130달러로 지정한다.

        HotelRoomResponse response = HotelRoomResponse.of(hotelRoomId, originalPrice, HotelRoomType.DOUBLE, roomNumber); // 응답 객체를 생성한다.

		// 만약 fromDate, toDate 파라미터가 모두 존재한다면 응답객체에 예약내용을 추가한다.
        if(Objects.nonNull(fromDate) && Objects.nonNull(toDate)) {
            fromDate.datesUntil(toDate.plusDays(1))
                    .forEach(date -> response.reservedAt(date));
        }

        return response;
    }

    @DeleteMapping("/hotels/{hotelId}/rooms/{roomNumber}")
    public DeleteResultResponse deleteHotelRoom(@PathVariable Long hotelId, @PathVariable String roomNumber) {
        log.info("Delete Request. hotelId={}, roomNumber={}", hotelId, roomNumber);

        return new DeleteResultResponse(Boolean.TRUE, "success");
    }
}

 

- @RestController는 @Controller와 @ResponseBody를 합친 어노테이션 이다. 스프링 빈으로 등록되어 JSON 메지시 형태로 리턴하게 된다.

- @GetMapping() : 명세에서 정해진 URL 형식의 요청이 GET 형식으로 들어왔을 때 처리하는 사용자 메서드를 매핑해준다.

  1. @PathVariable : URL 중 특정한 위치에 있는 데이터를 추출한다.

  2. @RequestParam() : HTTP 파라미터로 전달되는 데이터를 추출한다. value는 파라미터의 이름을 뜻한다.

  3. @DateTimeFormat : 전달되는 날짜 인자 값을 LocalDate 객체로 파싱한다.

  4. 사용자가 생성한 HotelRoomResponse 객체를 JSON 형태로 리턴한다.

 

- @DeleteMapping() : 명세에서 정해진 URL 형식의 요청이 DELETE 형식으로 들어왔을 때 처리하는 사용자 메서드를 매핑해준다.

  1. @PathVariable을 통해 URL의 데이터를 추출한다.

  2. 지금은 DB와 연결되지 않아 예약정보를 저장할 수 없기에, 간단히 해당 요청이 수행되었다는 로그만 서버에 남긴다.

  3. 사용자가 생성한 DeleteResultREsponse 객체를 JSON 형태로 리턴한다.

3.  DTO 구현

- DTO란 Data Transfer Object, 즉 데이터 전달을 위한 객체를 뜻한다. 위의 컨트롤러에서 사용한 반환 객체인 HotelRoomResponse와  DeleteResultREsponse 객체를 구현해본다.

@Data
public class HotelRoomResponse {

    @JsonProperty("id") // Json 객체의 이름을 지정하는데 사용
    @JsonSerialize(using = ToStringSerializer.class) // Json 객체로 변환 할 때 타입을 String 으로 변환한다.
    private Long hotelRoomId;

    @JsonSerialize(using = ToDollarStringSerializer.class) // Json 객체로 변환 할 때 타입을 커스텀한 ToDollarString 으로 변환한다.
    private BigDecimal originalPrice;
    private HotelRoomType hotelRoomType;
    private String roomNumber;

    private List<Reservation> reservations;

    public HotelRoomResponse(Long hotelRoomId, BigDecimal originalPrice, HotelRoomType hotelRoomType, String roomNumber) {
        this.hotelRoomId = hotelRoomId;
        this.originalPrice = originalPrice;
        this.hotelRoomType = hotelRoomType;
        this.roomNumber = roomNumber;
        reservations = new ArrayList<>();
    }

    public static HotelRoomResponse of(Long hotelRoomId, BigDecimal originalPrice, HotelRoomType hotelRoomType, String roomNumber) {
        return new HotelRoomResponse(hotelRoomId,originalPrice, hotelRoomType, roomNumber);
    }

    public void reservedAt(LocalDate reservedAt) {
        reservations.add(new Reservation(IdGenerator.create(), reservedAt));
    }

    @Data
    private static class Reservation {
        @JsonProperty("id")
        @JsonSerialize(using = ToStringSerializer.class)
        private Long reservationId;

        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
        private LocalDate reserveDate;

        @Builder
        public Reservation(Long reservationId, LocalDate reserveDate) {
            this.reservationId = reservationId;
            this.reserveDate = reserveDate;
        }
    }
}

@Data
public class DeleteResultResponse {
    private boolean success;
    private String message;

    public DeleteResultResponse(boolean success, String message) {
        this.success = success;
        this.message = message;
    }
}

 

- InnerClass인 Reservation 또한 하나의 DTO이다.

- @JsonProperty는 json으로 클라이언트에게 반환할 때 key값을 괄호 안의 값으로 설정해준다.

- @JsonSerialize는 json으로 클라이언트에게 반환할 때 괄호안에 지정한 형태로 설정해준다.

- @JsonFormat은 객체를 사용자가 원하는 형태의 포맷으로 바꾸어준다.

 

4.  결과

http://localhost:8080/hotels/123/rooms/12345?fromDate=20220101&toDate=20220102

 

위와 같이 서버에 요청하게 되면, 다음과 같은 결과를 반환해준다.

{
  "originalPrice": "130.00",
  "hotelRoomType": "double",
  "roomNumber": "12345",
  "reservations": [
    {
      "reserveDate": "2022-01-01",
      "id": "16711785287875610"
    },
    {
      "reserveDate": "2022-01-02",
      "id": "16711785287871245"
    }
  ],
  "id": "16711785287845223"
}

 

저작자표시 비영리 변경금지 (새창열림)

'공부 > Spring Boot' 카테고리의 다른 글

[스프링 부트 공부 일지] 3. 스프링에서 REST API 개발하기 (3)  (0) 2022.12.17
[스프링 부트 공부 일지] 3. 스프링에서 REST API 개발하기 (2)  (0) 2022.12.16
[스프링 부트 공부 일지] 2. 스프링 웹 MVC  (0) 2022.12.15
[스프링 부트 공부 일지] 1. 스프링 애플리케이션  (0) 2022.12.15
[스프링 부트 공부 일지] 0. 공부를 시작하며  (0) 2022.12.13
'공부/Spring Boot' 카테고리의 다른 글
  • [스프링 부트 공부 일지] 3. 스프링에서 REST API 개발하기 (3)
  • [스프링 부트 공부 일지] 3. 스프링에서 REST API 개발하기 (2)
  • [스프링 부트 공부 일지] 2. 스프링 웹 MVC
  • [스프링 부트 공부 일지] 1. 스프링 애플리케이션
뚝딱뚝딱2
뚝딱뚝딱2
  • 뚝딱뚝딱2
    개발도상국
    뚝딱뚝딱2
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 공부
        • Java
        • Spring Boot
        • LORA
      • Web
        • 인스타 클론 코딩
        • GPT 응답 API 서버
        • Spring Boot 예외 처리
        • 코테 준비용 서비스 만들기
      • DevOps
        • 쿠버네티스
        • 서버 만들기
      • 코딩테스트
        • 알고리즘
      • 교육
        • 스파르타코딩클럽 - 내일배움단
        • 혼자 공부하는 컴퓨터 구조 운영체제
      • 잡다한것
  • 블로그 메뉴

    • 홈
  • 링크

    • GITHUB
  • 공지사항

  • 인기 글

  • 태그

    예외
    Java
    mapstruct
    인스타그램
    백준
    react
    스프링부트
    OpenAI API
    오블완
    클론코딩
    티스토리챌린지
    리액트
    쿠버네티스
    chat GPT
    REST API
    클러스터
    Entity
    MSA
    spring boot
    스프링 부트
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
뚝딱뚝딱2
[스프링 부트 공부 일지] 3. 스프링에서 REST API 개발하기 (1)
상단으로

티스토리툴바