구체적인 예외처리

김태민·2025년 12월 9일

문제 상황

외부 API를 호출하는 헬퍼 메서드에서 HTTP 응답 코드를 하드코딩으로 처리했습니다.

개선 전 코드

private String callApi(String url) {
    try {
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .build();

        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

        // 문제 1: 200만 성공으로 처리 (201, 202 등은 실패 처리됨)
        if (response.statusCode() == 200) {
            return response.body();
        }
        // 문제 2: 404만 데이터 없음으로 처리 
        else if (response.statusCode() == 404) {
            return null;
        } else {
            logger.error("API 호출 실패 - 상태 코드: {}", response.statusCode());
            return null;
        }

    } catch (Exception e) {  // 문제 3: Exception이 너무 광범위함
        logger.error("API 호출 중 예외 발생", e);
        return null;
    }
}

피드백

제가 깊게 생각하지 못했던 부분들을 지적받았습니다.

  1. 200번대 응답을 모두 성공으로 처리하지 못함
    • 201 Created, 202 Accepted, 204 No Content 등도 성공인데 실패 처리됨
  2. 404만 특별 처리
    • 400 Bad Request, 401 Unauthorized 등 다른 4xx 에러는 일반 에러로 처리됨
  3. Exception 처리가 너무 광범위
    • 모든 예외를 같은 방식으로 처리 (구체적인 대응 불가)

개선 후 코드

private String callApi(String url, HttpMethod method) {
      try {
          HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
                  .uri(URI.create(url));

          HttpRequest request = requestBuilder.build();
          HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

          logger.debug("API 응답 상태: {} ({}) - URL: {}", response.statusCode(), method, url);

          // 개선 1: HttpStatus로 200대 응답 모두 처리
          HttpStatus httpStatus = HttpStatus.resolve(response.statusCode());
          if (httpStatus != null && httpStatus.is2xxSuccessful()) {
              return response.body();
          }
          // 개선 2: 모든 4xx 에러를 클라이언트 에러로 처리
          else if (httpStatus.is4xxClientError()) {
              return null; // 데이터 없음
          } else {
              logger.error("API 호출 실패 - 상태 코드: {}, URL: {}", response.statusCode(), url);
              return null;
          }

      // 개선 3: Exception을 구체적으로 분리
      } catch (IOException e) {
          logger.error("API 호출 중 I/O 예외 발생 - URL: {}", url, e);
          return null;
      } catch (InterruptedException e) {
          logger.error("API 호출 중 인터럽트 발생 - URL: {}", url, e);
          Thread.currentThread().interrupt();
          return null;
      } catch (IllegalArgumentException e) {
          logger.error("잘못된 HTTP 메서드 또는 URL - URL: {}, Method: {}", url, method, e);
          return null;
      } catch (Exception e) {
          logger.error("API 호출 중 예상치 못한 예외 발생 - URL: {}, Method: {}", url, method, e);
          return null;
      }
  }

개선 사항

  1. is2xxSuccessful() 메서드 활용

    if (httpStatus.is2xxSuccessful()) {
        return response.body();
    }

    200번대 응답 모두 성공으로 처리 가능!

  2. is4xxClientError() 메서드로 클라이언트 에러 통합 처리

  else if (httpStatus.is4xxClientError()) {
      return null; // 데이터 없음
  }

400번대 모든 클라이언트 에러 처리 가능!

  1. Exception 구체화로 정확한 에러 처리

    catch (IOException e) {
               logger.error("API 호출 중 I/O 예외 발생 - URL: {}", url, e);
               return null;
           } catch (InterruptedException e) {
               logger.error("API 호출 중 인터럽트 발생 - URL: {}", url, e);
               Thread.currentThread().interrupt();
               return null;
           } catch (IllegalArgumentException e) {
               logger.error("잘못된 HTTP 메서드 또는 URL - URL: {}, Method: {}", url, method, e);
               return null;
           } catch (Exception e) {
               logger.error("API 호출 중 예외 발생 - URL: {} Method: {}", url, method, e);
               return null;
           }

    IOException - 입출력 예외
    InterruptedException - 인터럽트 예외
    IllegalArgumentException - 잘못된 인자 예외


결론

HTTP 상태 코드를 하드코딩(== 200, == 404)하는 대신 Spring의 HttpStatus 클래스를 활용하면

  • 모든 성공/에러 케이스를 빠짐없이 처리
  • 코드 가독성 향상
  • 예외 처리 구체화

단순해 보이는 상태 코드 처리도 프레임워크가 제공하는 유틸리티를 활용하면 더 견고한 코드를 작성할 수 있습니다!

profile
빠르게 성장하는 개발자

0개의 댓글