Response에 이어서 exception_handler를 이용하여 기본 예외 포맷이나 응답 구조를 사용자화 하려고한다.
들어가기에 앞서 exception_handler란 무엇인가?
'exception_handler'는 DRF의 예외처리 기능으로 API에서 발생한 예외를 처리하고 사용자 지정 응답을 생성하는 역할을 한다. 기본적으로 exception_handler를 사용하여 예외처리를해도 아무런 문제가 없지만 이를 재정의해서 사용자 지정 로직을 적용시켜 보려고한다.
예외처리를 커스터마이징 하기 위한 절차로는
1. exception_handler를 재 정의한다.
2. 예외를 처리하고 사용자 지정 응답을 생성하는 로직을 구현한다.
3. 설정 파일에서 재정의한 핸들러를 등록한다.
아래는 1번 exception_handler를 재정의한 내용이다. 조금 길고 어려워 보이지만 이해하면 생각보단 쉬운 내용이였다.
#core.exceptions.py
from rest_framework import status
from rest_framework.views import exception_handler
from rest_framework.exceptions import APIException
from core.constants import SystemCodeManager
from core.responses import Response
def custom_exception_handler(exc, context):
response = exception_handler(exc, context)
if isinstance(exc, CustomAPIException):
return response
if response is not None:
response.data["status_code"] = response.status_code
return Response(
data={
"code": SystemCodeManager.get_message("base_code", "UNKNOWN_SERVER_ERROR")
},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
class CustomAPIException(APIException):
def __init__(self, **kwargs):
self.status_code = kwargs.get("status", 400)
self.code = kwargs.get(
"code", SystemCodeManager.get_message("base_code", "BAD_REQUEST")
)
self.detail = self.code[1]
def raise_exception(**kwargs):
raise CustomAPIException(**kwargs)
우선 예외가 발생하는 부분에서 raise_exception을 호출해서 인자 값으로 예외 코드를 넘겨주면, 그 코드를 CustomAPIException으로 넘겨준 이후 CustomAPIException에서 예외 코드를 가공하여 custom_exception_handler로 넘겨준다.
custom_exception_handler에서는 받은 데이터가 CustomAPIException 양식인지 확인하고 앞의 글에서 구현했던 custom한 Response로 넘겨준다.
만역 받은 데이터가 CustomAPIException 양식이 아닐 경우, 우리가 커스텀해준 error 코드와 일치하는 값이 없는 에러라는 이야기기 때문에 '알 수 없는 서버 에러'를 출력해준다.
여기서 SystemCodeManager.get_message("base_code", "UNKNOWN_SERVER_ERROR")는 커스터 마이징해준 에러 코드를 호출해주는 부분으로 아래 코드 처럼 구현되어 있다.
import json
class SystemCodeManager:
"""
ex)
status_code, message_ko = SystemCodeManager.get_message("auth_code", "SUCCESS")
status_code, message_en = SystemCodeManager.get_message("auth_code", "SUCCESS", 'en')
"""
@classmethod
def get_message(cls, system_code_type, message, lang="ko"):
filepath = f"core/system_codes/{system_code_type}.json"
messages = cls.load_messages(filepath)
if message in messages:
data = messages[message]
if lang in data:
return data["code"], data[lang]
else:
return SystemCodeManager.get_message("base_code", "SYSTEM_CODE_ERROR")
return None
@staticmethod
def load_messages(filepath):
with open(filepath, "r", encoding="utf-8") as file:
return json.load(file)["SYSTEM_CODE"]
이 코드는 json에 저장된 에러 코드들을 읽어주는 역할이다.
- get_message 메서드:
- system_code_type: 시스템 코드 유형을 나타내는 문자열입니다. 예를 들어 "auth_code" 또는 "base_code"와 같은 값을 사용할 수 있습니다.
- message: 시스템 코드 메시지를 나타내는 문자열입니다. 예를 들어 "SUCCESS", "BAD_REQUEST" 등이 될 수 있습니다.
- lang: 언어 코드를 나타내는 문자열입니다. 기본값은 "ko"로 한국어 메시지를 반환합니다. 옵션으로 "en"을 전달하면 영어 메시지를 반환합니다. 이 메서드는 시스템 코드 및 메시지가 포함된 JSON 파일을 로드하고, 해당 메시지에 대한 코드와 언어별 메시지를 반환합니다. 만약 해당 메시지가 없으면 기본적으로 "SYSTEM_CODE_ERROR" 메시지를 반환합니다.
- load_messages 메서드:
- filepath: 시스템 코드 및 메시지가 포함된 JSON 파일의 경로를 나타내는 문자열입니다.
- 이 메서드는 주어진 파일 경로에서 시스템 코드 및 메시지를 로드하고 딕셔너리 형태로 반환합니다.
이후 settings에서 예외처리 핸들러를 변경해주고 아래처럼 호출해서 사용해주기만 하면 된다.
REST_FRAMEWORK = {
...,
...,
"EXCEPTION_HANDLER": "core.exceptions.custom_exception_handler",
}
raise_exception(
code=SystemCodeManager.get_message("auth_code", "EMAIL_ALREADY")
)
참고
'BackEnd > Django, DRF' 카테고리의 다른 글
[TEST] 테스트 DB 없이 Django에서 유닛 테스트 수행하기 (0) | 2024.05.14 |
---|---|
[CORS] DRF에서 CORS 문제 해결 및 테스트 방법 (0) | 2024.05.14 |
[Custom] DRF Custom Response fomat (Response) (1) | 2024.05.01 |
[Custom] DRF Custom Render fomat (JSONRenderer) (0) | 2024.04.29 |
[ORM] Django의 ORM이란 무엇인가? (0) | 2024.04.21 |