minOS

API 예외 처리 - 시작 본문

TIL/김영한의 스프링 MVC 2편 - 백엔드 웹 개발 핵심 기술

API 예외 처리 - 시작

minOE 2024. 10. 2. 21:02
728x90

API 예외 처리 - 시작

목표

API 경우에는 생각할 내용이 많다. 오류 페이지는 단순히 고객에게 오류 화면을 보여주고 끝이지만, API

오류 상황에 맞는 오류 응답 스펙을 정하고, JSON으로 데이터를 내려주어야 한다.
앱에서 앱 , 기업 간 시스템 통신하기때문에


지금부터 API 경우 어떻게 예외 처리를 하면 좋은지 알아보자.

API 오류 페이지에서 설명했던 처럼 처음으로 돌아가서 서블릿 오류 페이지 방식을 사용해보자.


WebServerCustomizer 주석 풀고 다시 동작

@Component
public class WebServerCustomizer implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
    @Override
    public void customize(ConfigurableWebServerFactory factory) {

        ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error-page/404");
        ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error-page/500");

        ErrorPage errorPageEx = new ErrorPage(RuntimeException.class , "/error-page/500");
        //해당 예외와 자식 타입의 오류 함게 처리해줌

        factory.addErrorPages(errorPage404,errorPage500,errorPageEx);


    }
}

`WebServerCustomizer` 다시 사용되도록 하기 위해 `@Component` 애노테이션에 있는 주석을 풀자

이제 WAS 예외가 전달되거나, `response.sendError()` 호출되면 위에 등록한 예외 페이지 경로가 호출된다.

 

ApiExceptionController - API 예외 컨트롤러

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class ApiExceptionController {
    @GetMapping("/api/members/{id}")
    public MemberDto getMember(@PathVariable("id") String id){
        if (id.equals("ex")){
            throw new RuntimeException("잘못된 사용자");
            //500 html 반환 문제를 해결하려면 오류 페이지 컨트롤러도 JSON응답 할 수 있도록 수정해야한다.

        }

        return new MemberDto(id,"hello "+id);
    }

    @Data
    @AllArgsConstructor
    static class MemberDto{
        private String memberId;
        private String name;
    }

}


postman으로 api 실행

 

오류가 발생하면 

html이 반환된다. 이것은 기대한 바가 아니다. 클라이언트는 정상 요청이든, 오류 요청이든 JSON이 반환되기를 기대한다. 웹 브라우저가 아닌 이상 HTML을 직접 받아서 할 수 있는 것은 별로 없다.문제를 해결하려면 오류 페이지 컨트롤러도 JSON 응답을 할 수 있도록 수정해야 한다.


ErrorPageController - API 응답 추가
    @RequestMapping(value = "/error-page/500", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Map<String,Object>> errorPage500Api(
            HttpServletRequest request,HttpServletResponse response){
        log.info("API errorPage 500");

        Map<String,Object> result = new HashMap<>();
        Exception ex = (Exception) request.getAttribute(ERROR_EXCEPTION);
        result.put("status",request.getAttribute(ERROR_STATUS_CODE));
        result.put("message",ex.getMessage());


       Integer statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);

       return new ResponseEntity<>(result, HttpStatus.valueOf(statusCode));

    }​

 

`produces = MediaType.APPLICATION_JSON_VALUE` 뜻은 클라이언트가 요청하는 HTTP Header

`Accept` 값이 `application/json` 해당 메서드가 호출된다는 것이다. 결국 클라어인트가 받고 싶은 미디어

타입이 json이면 컨트롤러의 메서드가 호출된다.

응답 데이터를 위해서 `Map` 만들고 `status` , `message` 키에 값을 할당했다. Jackson 라이브러리는 `Map`

JSON 구조로 변환할 있다.

`ResponseEntity` 사용해서 응답하기 때문에 메시지 컨버터가 동작하면서 클라이언트에 JSON 반환된다.

포스트맨을 통해서 다시 테스트 해보자.

HTTP Header `Accept` `application/json` 것을 확인하자.

 

HTTP Header `Accept` `application/json` 아니면, 기존 오류 응답인 HTML 응답이 출력되는 것을 확인

있다.

 

 

728x90