우아한테크코스/모락 프로젝트

존재하지 않는 API 요청 커스터 마이징하기

자바지기 2022. 8. 16. 15:45
반응형

존재하지 않는 API 요청을 커스터 마이징을 한 이유

 

기존에 백엔드 서버로 존재하지 않는 API가 요청되면 다음과 같은 응답을 건내주었다.

 

존재하지 않는 API가 요청 시 404 NOT FOUND를 응답한다.

 

모락 프로젝트에서는 이런 상황 뿐만 아니라 리소스가 존재하지 않는 경우에도 NOT FOUND와 error code를 던져준다.

따라서 존재하지 않는 API가 요청 상황에도 error code를 통해 에러 구분을 하고 싶었다. (참고 글)

 

커스터 마이징 과정

우선 커스터 마이징 이전에 존재하지 않는 API가 요청 시 어떻게 진행되는 지 DispatcherServlet을 확인해보자.

존재하지 않는 API로 요청을 보내보았다.

 

http://localhost:8080/invalid-api

 

위의 요청을 보내면 DispatcherServlet의 mappedHandeler에 ResourceHttpRequestHandler가 매핑되었다.

즉, 요청에 응답할 수 있는 컨트롤러가 존재하지않으면 기본적으로 ResourceHttpRequestHandler가 매핑된다.

 

ResourceHttpRequestHandler가 요청에 해당하는 resource를 찾는다.

이에 해당하는 resource가 존재하지 않으므로 맨 위에서 보았던 404 NOT FOUND가 응답되었던 것이다.

 

우리의 목표는 존재 하지 않는 API가 요청되면 매핑되는 handler가 없게 되어 noHandleFound 메소드를 실행하는 것 이다.

noHandleFound 메소드는 위와 같다. 우리는 NoHanderFoundException을 throw 해야한다.

우리는 throw한 NoHandlerFoundException를 catch하여 custom error code를 응답할 수 있다.

 

이를 달성하기 위해서는 일단 mappedHandler가 null이어야한다. 즉, 매핑되는 핸들러가 없어야한다.

이를 위해 기본적으로 ResourceHttpRequestHandler가 매핑되는 것을 수정해보자.

ResourceHttpRequestHandler의 매핑되는 과정은 다음과 같다.

 

1. DelegatingWebMvcConfiguration 클래스에서 addResourceHandlers를 진행한다.

 

2. 등록해준 WebMvcConfigure들을 돌면서 resourceHandler를 실행한다.

 

3. 이때 resourceProperties.isAddMappings가 false라면 resourceHandler가 등록되지 않는다.

 

isAddMappings가 false가 되려면 WebProperties의 Resources 내부에 있는 addMappingsfalse여야한다.

 

기본적으로 addMappings는 true로 선언되어있다.

따라서 기본적으로 resourceHandler가 등록된다.

 

resourceHandler 등록 과정.gif

 

이를 해결하기 위해 application.yml 파일을 통해 properties를 관리해보자.

application.yml에 위와 같이 작성한다. addMapings를 false로 설정한다.

 

이후 다시 디버깅을 해보면 addMappings가 false로 변한 것을 알 수 있다.

 

 

이제 다시 본론으로 돌아가면 ResourceHttpRequestHandler가 매핑되지 않아서 mappedHandlernull일 것이다. 다시 한번 http://localhost:8080/invalid-api 로 요청을 보내보면 다음과 같다.

mappedHandler가 null이기 때문에 바로 밑의 noHandlerFound 메서드가 실행될 것이다.

 

그런데 noHandlerFound메서드 내부에서 this.throwExceptionIfNotHandlerFound 가 기본적으로 false 값을 가지고 있으므로 NoHandlerFoundException을 던지는 대신에

response.sendError(HttpServletResponse.SC_NOT_FOUND) 를 실행하게된다.

 

따라서 결국 응답은 맨 위의 사진과 같이 나타나게 된다.

 

 

따라서 NoHandlerFoundException 를 throw 하려면 this.throwExceptionIfNotHandlerFound 를 true로 변경해야한다. 이 또한 application.yml 파일을 수정하면 된다

 

 

이제 다시 http://localhost:8080/invalid-api 로 요청을 보내면 응답이 다음과 같이 나타난다.

 

 

 

DispatcherServlet에서 NoHandlerFoundException을 던진 것을 확인할 수 있다

이제 이 Exception을 ControllerAdvice에서 catch만 하면 된다.

 

 

다시 http://localhost:8080/invalid-api 로 요청을 보내면 다음과 같은 응답을 받을 수 있다.

이제 우리가 원하는 에러 코드와 메시지를 넘겨줄 수 있게 되었다 ! 

 

이로써 프론트 개발자는 코드를 확인하고 어떤 페이지를 띄울 지 결정할 수 있다 !

 

그런데 문제가 하나 있다. ResourceHttpRequestHandler가 매핑되지 않기 때문에 우리가 보고자 하는 정적파일에 접근할 수 없게 되었다. 즉 이 상태에서는 정적 파일인 rest docs 파일을 볼 수 없게 되었다.

따라서 rest docs 파일을 볼 수 있도록 설정을 변경하였다.

WebConfig를 구현한 WebMvcConfigurer 에서 다음과 같이 addResourceHandlers 메서드를 재정의했다.

/docs/index.html 로 접근 시에만 ResourceHandler가 동작하도록 변경하였다.

 

 

반응형