본문 바로가기

Education/인프런 워밍업 클럽(BE 0기)

인프런 워밍업 클럽 - BE 0기, 과제 #2

목차

     

    과제

    문제1. 두 수를 입력하면, 다음과 같은 결과가 나오는 GET API를 만들어 보자!

    • path: /api/v1/calc
    • 쿼리 파라미터: num1, num2
    {
        "add": 덧셈결과,
        "minus": 뺄셈결과,
        "multiply": 곱셈결과
    }

     

    풀이

    1. 첫 번째 시도 (실패)

    더보기

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.group.libraryapp.dto.study;
     
    public class CalculatorRequest {
     
        private int number1;
        private int number2;
     
        public CalculatorRequest(int number1, int number2) {
            this.number1 = number1;
            this.number2 = number2;
        }
     
        public int getNumber1() {
            return number1;
        }
     
        public int getNumber2() {
            return number2;
        }
    }
     
    cs

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    package com.group.libraryapp.controller.study;
     
    import com.group.libraryapp.dto.study.CalculatorRequest;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
     
    @RestController
    public class StudyController {
     
        @GetMapping("/api/v1/calc")
        public int[] calculateTwoNumber(CalculatorRequest request) {
     
            int sum = getSum(request);
            int minus = getMinus(request);
            int multiply = getMultiply(request);
     
            int[] result = {sum, minus, multiply};
            
            return result;
        }
     
        public int getSum(CalculatorRequest request) {
            return request.getNumber1() + request.getNumber2();
        }
        public int getMinus(CalculatorRequest request) {
            return request.getNumber1() - request.getNumber2();
        }
     
        public int getMultiply(CalculatorRequest request) {
            return request.getNumber1() * request.getNumber2();
        }
    }
     
    cs

     

    파라미터를 객체로 받기 위해 CalculatorRequest 클래스를 만들고, 결과 값은 3개가 반환돼야 하니 배열로 생각해서 문제를 풀어봤다.

    결과는 실패..

    반환 값이 JSON이 아닌 배열 형태로 나온다. 배열이 아닌 다른 형태로 결과 값을 반환해 줘야 한다.

    2. 두 번째 시도

    결과 값을 JSON 형태로 반환하려면 어떻게 해야 되지?

    강의에서 객체를 반환하니까 JSON 형태로 반환이 된 게 기억나서 객체를 만들어서 반환해 보기로 했다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package com.group.libraryapp.dto.study;
     
    public class CalculatorResponse {
        
        private int add;
        private int minus;
        private int multiply;
     
        public CalculatorResponse(int addint minus, int multiply) {
            this.add = add;
            this.minus = minus;
            this.multiply = multiply;
        }
     
        public int getAdd() {
            return add;
        }
     
        public int getMinus() {
            return minus;
        }
     
        public int getMultiply() {
            return multiply;
        }
    }
     
    cs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package com.group.libraryapp.controller.study;
     
    import com.group.libraryapp.dto.study.CalculatorRequest;
    import com.group.libraryapp.dto.study.CalculatorResponse;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
     
    @RestController
    public class StudyController {
     
        @GetMapping("/api/v1/calc")
        public CalculatorResponse calculateTwoNumber(CalculatorRequest request) {
     
            int sum = getSum(request);
            int minus = getMinus(request);
            int multiply = getMultiply(request);
     
            CalculatorResponse result = new CalculatorResponse(sum, minus, multiply);
     
            return result;
        }
     
        public int getSum(CalculatorRequest request) {
            return request.getNumber1() + request.getNumber2();
        }
        public int getMinus(CalculatorRequest request) {
            return request.getNumber1() - request.getNumber2();
        }
     
        public int getMultiply(CalculatorRequest request) {
            return request.getNumber1() * request.getNumber2();
        }
    }
     
    cs

     

    결과는!!🧐🧐

    짜라란. JSON 형태로 잘 나왔다!!

     


    문제2. 날짜를 입력하면, 몇 요일인지 알려주는 GET API를 만들어 보자!

    path와 쿼리 파라미터는 임의로 만들어도 상관없다.

    {
        "dayOfTheWeek": "MON"
    }

     

    풀이

    문제 팁에 친절하게 자바8에서 추가된 LocalDate 객체에 대해 찾아보고 풀어보라고 나와있다.

    자바 문서를 확인해 보자..

    https://docs.oracle.com/javase/8/docs/api/

     

    Java Platform SE 8

     

    docs.oracle.com

    getDayOfWeek() 메서드가 요일을 반환해 주는 것 같다. 바로 적용해 보았다.

     

    1. 첫 번째 시도(실패)

    더보기
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package com.group.libraryapp.controller.study;
     
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
     
    import java.time.DayOfWeek;
    import java.time.LocalDate;
     
    @RestController
    public class StudyController {
        
        @GetMapping("/api/v1/day-of-the-week")
        public DayOfWeek getDayOfTheWeek(@RequestParam LocalDate date) {
            return date.getDayOfWeek();
        }
    }
     
    cs

     

    역시나 실패!😂

    400에러가 발생한거면 클라이언트 요청이 잘못된 걸로 확인된다.

    2. 두 번째 시도

    쿼리 파라미터는 문자열로 넘어가는 게 생각났다!

    쿼리 파라미터인 date를 받아서 LocalDate 객체로 변환해 준 다음에 LocalDate에 넣어줘야 되는 것 같다.

    검색해 보니 스프링 어노테이션인 @DateTimeFormat을 사용해서 전달된 쿼리 파라미터를 자동으로 LocalDate 객체로 변환해 주는 방법과 String으로 파라미터를 받은 후 문자열로 전달된 값을 LocalDate 객체로 변환하는 방법이 있다.

     

    2.1. 어노테이션을 사용하는 방식

    1
    2
    3
    4
    @GetMapping("/api/v1/day-of-the-week")
    public DayOfWeek getDayOfTheWeek(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) {
       return date.getDayOfWeek();
    }
    cs

     

    2.2 String을 LocalDate 객체로 변환하는 방식

    1
    2
    3
    4
    5
    6
    7
        @GetMapping("/api/v1/day-of-the-week")
        public DayOfWeek getDayOfTheWeek(@RequestParam String date) {
     
            LocalDate localDate = LocalDate.parse(date, DateTimeFormatter.ISO_DATE);
     
            return localDate.getDayOfWeek();
        }
    cs

     

    여기서 iso = DateTimeFormat.ISO.DATE, DateTimeFormatter.ISO_DATE와 같은 포맷은 ISO-8601형식을 사용하는 방법 중 하나로, "yyyy-MM-dd"로 년월일을 나타내는 날짜 형식이라고 한다.

    LocalDate.parse() 메서드는 ISO-8601 형식을 이용해서 문자열을 LocalDate 객체로 변환해 주기 때문에 "yyyy-MM-dd" 형식의 문자열을 보낼 때는 명시적으로 지정할 필요가 없다고 한다. (스프링은 기본적으로 이 형식을 사용한다고 함.)

     

    결과는!!!!

    요일이 잘 구해져 나왔다!!!!

     

    하지만.. 원하는 결과값은 JSON 타입으로 key:value 형태로 나와야 되는데 요일만 구해져서 나왔다.

    이번에도 역시 객체를 만들어서 반환해 보겠다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package com.group.libraryapp.dto.study;
     
    public class DayOfTheWeekResponse {
        
        private String dayOfWeek;
     
        public DayOfTheWeekResponse(String dayOfWeek) {
            this.dayOfWeek = dayOfWeek;
        }
     
        public String getDayOfWeek() {
            return dayOfWeek;
        }
    }
    cs
    1
    2
    3
    4
    5
    6
    7
    8
        @GetMapping("/api/v1/day-of-the-week")
        public DayOfTheWeekResponse getDayOfTheWeek(@RequestParam String date) {
     
            LocalDate localDate = LocalDate.parse(date);
            DayOfWeek dayOfWeek = localDate.getDayOfWeek();
     
            return new DayOfTheWeekResponse(dayOfWeek.toString());
        }
    cs

     

     

    결과는 성공이다!!

     


     

    문제3. 여러 수를 받아 총 합을 반환하는 POST API를 만들어 보자!

    API에서 받는 Body형태


    {
        "numbers": [1, 2, 3, 4, 5]
    }

    반환결과

    15

     

    풀이

    요청을 받는 DTO에서 List를 갖고 있으면 JSON의 배열을 받을 수 있다고 팁이 적혀있다.

    요청받을 때 사용할 DTO를 생성하고, API를 만들어 보겠다.

    1. 첫 번째 시도(실패)

    더보기
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package com.group.libraryapp.dto.study;
     
    import java.util.List;
     
    public class AddNumbersRequest {
     
        private List<Integer> numbers;
        
     
        public AddNumbersRequest(List<Integer> numbers) {
            this.numbers = numbers;
        }
     
        public List<Integer> getNumbers() {
            return numbers;
        }
     
    }
    cs

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package com.group.libraryapp.controller.study;
     
    import com.group.libraryapp.dto.study.AddNumbersRequest;
    import org.springframework.web.bind.annotation.*;
    import java.util.List;
     
    @RestController
    public class StudyController {
     
        @PostMapping("/api/v1/addNumbers")
        public int addNumbers(@RequestBody AddNumbersRequest request) {
            List<Integer> numbers = request.getNumbers();
            
            int sum = 0;
            for (Integer number : numbers) {
                sum += number;
            }
            
            return sum;
        }
    }
     
    cs

     

    DTO를 생성하고 api를 호출했는데 500에러가 발생했다.

    콘솔에 출력된 에러 메시지는

    ERROR 90456 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class cohttp://m.group.libraryapp.dto.study.AddNumbersRequest]; nested exception is cohttp://m.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `cohttp://m.group.libraryapp.dto.study.AddNumbersRequest` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

     

    AddNumbersRequest 객체를 생성할 때 기본 생성자를 호출하지 못해서 발생하는 에러였다!!

    2. 두 번째 시도

    AddNumbersRequest에 기본 생성자 추가한 뒤 다시 실행해봤다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.group.libraryapp.dto.study;
     
    import java.util.List;
     
    public class AddNumbersRequest {
     
        private List<Integer> numbers;
     
        public AddNumbersRequest() {
        }
     
        public AddNumbersRequest(List<Integer> numbers) {
            this.numbers = numbers;
        }
     
        public List<Integer> getNumbers() {
            return numbers;
        }
        
    }
     
    cs

     

    결과는 성공!!!!


    오늘 과제를 하면서.. 

    첫 번째 시도에 성공한 문제가 하나도 없다는 것에 좌절했다..🥲

    그래도 원하는 결과는 아니더라도 데이터 반환까지는 성공했고, 실패하게 된 원인을 찾아가는 과정에서 더 자세히 배우는 단계가 된 것 같다.

    다음에는 더 잘하자! 화이팅!!!