Troubleshooting: 무엇이 문제였는가?/본캠프 3주 차: 일정 관리 앱 만들기

1단계: "컴퓨터가 200 OK라는데 [ ] 밖에 안 보여요."

writingforever162 2024. 12. 6. 12:54

[문제]

Postman으로 API가 잘 작동하는지 확인했는데, 막상 GET 메서드(method)를 실행하니 아무것도 나오지 않았다. 처음에는 오류인 줄 알고 심정이 철렁했는데, '200 OK'라는 Http 상태 메시지를 보니 원인이 어느 쪽인지 짐작할 수 있었다. 이번에 발생한 문제는 리턴(return), 즉 반환하는 부분을 제대로 작성하지 않아서 생긴 듯했다. 여기까지 추측한 다음에는 DTO(Data Transfer Object)나 엔티티(Entity)는 건너뛰고 각 레이어(layer)를 다시 찬찬히 읽었다. 

 

[원인]

package com.spring.weekthree.controller;

import com.spring.weekthree.dto.PlanRequestDto;
import com.spring.weekthree.dto.PlanResponseDto;
import com.spring.weekthree.service.PlanService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

// [1/3] Presentation Layer - controller

@RestController
@RequestMapping("/plans")
public class PlanController {
    // (1) 속성
    private final PlanService planService;

    // (2) 생성자
    public PlanController(PlanService planService) {
        this.planService = planService;
    }

    // (3) 기능
    @PostMapping
    public ResponseEntity<PlanResponseDto> createPlan(@RequestBody PlanRequestDto requestDto) {
        PlanResponseDto responseDto = planService.processSaveInService(requestDto);
        return new ResponseEntity<>(responseDto, HttpStatus.CREATED);
    }

    @GetMapping
    public ResponseEntity<List<PlanResponseDto>> readAllPlans() {
        List<PlanResponseDto> allPlans = planService.processViewService();

        return new ResponseEntity<>(allPlans, HttpStatus.OK);
    }
}
package com.spring.weekthree.service;

import com.spring.weekthree.dto.PlanRequestDto;
import com.spring.weekthree.dto.PlanResponseDto;
import com.spring.weekthree.entity.Plan;
import com.spring.weekthree.repository.PlanRepository;
import org.springframework.stereotype.Service;

import java.util.List;

// [2/3] Business Layer(Service Layer) - service

@Service
public class PlanServiceImpl implements PlanService {
    // (1) 속성
    private final PlanRepository planRepository;

    // (2) 생성자
    public PlanServiceImpl(PlanRepository planRepository) {
        this.planRepository = planRepository;
    }

    // (3) 기능
    @Override
    public PlanResponseDto processSaveInService(PlanRequestDto requestDto) {

        Plan plan = new Plan(
                requestDto.getName(),
                requestDto.getPassword(),
                requestDto.getPlannedDate(),
                requestDto.getTitle(),
                requestDto.getTask()
        );

        Plan savedPlan = planRepository.saveEachPlan(plan);

        return new PlanResponseDto(savedPlan);
    }

    @Override
    public List<PlanResponseDto> processViewService() {

        return planRepository.pullAllPlans();
    }
}
package com.spring.weekthree.repository;

import com.spring.weekthree.dto.PlanResponseDto;
import com.spring.weekthree.entity.Plan;
import org.springframework.stereotype.Repository;

import java.util.*;

// [3/3] Data Access Layer(Repository Layer) - repository

@Repository
public class PlanRepositoryImpl implements PlanRepository {
    // (1) 속성
    private final Map<Long, Plan> planList = new HashMap<>();

    // (2) 생성자

    // (3) 기능
    @Override
    public Plan saveEachPlan(Plan plan) {
        Long planId = planList.isEmpty() ? 1 : Collections.max(planList.keySet()) + 1;

        plan.setId(planId);

        planList.put(planId, plan);

        return plan;
    }

    @Override
    public List<PlanResponseDto> pullAllPlans() {
        List<PlanResponseDto> allPlans = new ArrayList<>();

        for (Plan plan : planList.values()) {
            PlanResponseDto responseDto = new PlanResponseDto(plan);
            allPlans.add(responseDto);
        }

        return List.of();
        // [오답] List.of();
        // [정답] allPlans;
    }
}

역시 짐작대로 원인은 인터페이스(interface) PlanRepository를 오버라이딩(overriding) 해온 PlanRepositoryImpl 클래스(class)에 있었다. add() 메서드까지 잘 사용해 놓고 allPlans가 아니라 List.of()를 반환했으니, 컴퓨터는 명령대로 잘 움직였을 뿐이었다.

 

[해결]

package com.spring.weekthree.repository;

import com.spring.weekthree.dto.PlanResponseDto;
import com.spring.weekthree.entity.Plan;
import org.springframework.stereotype.Repository;

import java.util.*;

@Repository
public class PlanRepositoryImpl implements PlanRepository {
    // (1) 속성
    private final Map<Long, Plan> planList = new HashMap<>();

    // (2) 생성자

    // (3) 기능
    @Override
    public Plan saveEachPlan(Plan plan) {
        Long planId = planList.isEmpty() ? 1 : Collections.max(planList.keySet()) + 1;

        plan.setId(planId);

        planList.put(planId, plan);

        return plan;
    }

    @Override
    public List<PlanResponseDto> pullAllPlans() {
        List<PlanResponseDto> allPlans = new ArrayList<>();

        for (Plan plan : planList.values()) {
            PlanResponseDto responseDto = new PlanResponseDto(plan);
            allPlans.add(responseDto);
        }

        return allPlans;
        /* 
        [수정 전] return List.of();
        [수정 후] return allPlans;
         */
    }
}

문제는 금방 해결했다. 정말 사소한 부분이지만, 오답 노트로 정리해 두면 같은 실수를 반복해도 최소한 '저번에도 이러지 않았나?' 기억을 더듬으며 오답 노트에서 찾을 수 있는 만큼, 기록으로 남겨두었다. '이런 실수를 했다고?' 느낀 동시에 팀 프로젝트를 하기 전에 저질러서 다행이라는 마음 또한 들었다.