프론트지만 Flask를 이용한 MVC 패턴으로 백엔드 API를 설계하고 있다. 우선 가장 먼저 내가 맡은 부분인
error_handler
를 만들어 전체적인 에러 관리를 한 곳에서 모여 처리할 수 있도록 만들었다.
import traceback
from flask import jsonify
from flask_request_validator import *
from flask_request_validator.error_formatter import demo_error_formatter
from flask_request_validator.exceptions import InvalidRequestError, InvalidHeadersError, RuleError
from utils.custom_exception import CustomUserError
from utils.response import error_response
def error_handle(app):
"""에러 핸들러
에러 처리하는 함수
Args:
app : __init__.py에서 파라미터로 app을 전달 받은 값
Returns:
json : error_response() 함수로 에러 메시지를 전달해서 반환 받고 return
"""
@app.errorhandler(Exception)
def handle_error(e):
traceback.print_exc()
return error_response("서버 상에서 오류가 발생했습니다.", "Exception", 500)
@app.errorhandler(AttributeError)
def handle_error(e):
traceback.print_exc()
return error_response("서버 상에서 오류가 발생했습니다.", "NoneType Error", 500)
@app.errorhandler(KeyError)
def handle_key_error(e):
traceback.print_exc()
return error_response("데이터베이스에서 값을 가져오는데 문제가 발생하였습니다.", "Database Key Error", 500)
@app.errorhandler(TypeError)
def handle_type_error(e):
traceback.print_exc()
return error_response("데이터의 값이 잘못 입력되었습니다", "Data Type Error", 500)
@app.errorhandler(ValueError)
def handle_value_error(e):
traceback.print_exc()
return error_response("데이터에 잘못된 값이 입력되었습니다.", "Data Value Error", 500)
# @app.errorhandler(err.OperationalError)
# def handle_operational_error(e):
# traceback.print_exc()
# return error_response(e, "에러")
@app.errorhandler(InvalidRequestError)
def data_error(e):
"""validate_params 정규식 에러
validate_params rules에 위배될 경우 발생되는 에러 메시지를 처리하는 함수
"""
traceback.print_exc()
dev_error_message = demo_error_formatter(
e)[0]['errors'], demo_error_formatter(e)[0]['message']
return error_response("형식에 맞는 값을 입력해주세요", dev_error_message, 400)
@app.errorhandler(CustomUserError)
def handle_error(e):
traceback.print_exc()
return error_response(e.error_message, e.dev_error_message, e.status_code)
먼저 error_handle
함수를 선언하고 그 안에 발생할 수 있는 에러들을 선언했다.
핵심적인 것은 마지막에 @app.errorhandler(CustomUserError)
이 부분이다.
이 부분은 말 그대로 우리가 개발하면서 발생할 수 있는 에러들을 직접 만들어 처리할 수 있도록 하는 부분이다.
그리고 view에서 아래와 같이 __init__.py
에 error_handle
을 등록해줘야 한다.
from .product_view import (
ProductView,
ProductDetailView,
)
from .order_view import (
OrderListView,
OrderView
)
from .account_view import (
SignUpView,
SignInView,
SignInSocialView
)
from utils.error_handler import error_handle
def create_endpoints(app, services):
product_service = services.product_service
order_service = services.order_service
account_service = services.account_service
# product
app.add_url_rule("/product/home",
view_func=ProductView.as_view('product_view', product_service),
methods=['GET','POST', 'PATCH'])
app.add_url_rule("/products/<product_code>",
view_func=ProductDetailView.as_view('product_detail_view', product_service),
methods=['GET','POST', 'PATCH'])
# order
app.add_url_rule("/orders",
view_func=OrderListView.as_view('order_list_view', order_service),
methods=['GET'])
app.add_url_rule("/orders/<int:order_detail_number>",
view_func=OrderView.as_view('order_view', order_service),
methods=['GET'])
# account
app.add_url_rule("/user/signup",
view_func=SignUpView.as_view('signup_view', account_service),
methods=['POST'])
app.add_url_rule("/user/signin",
view_func=SignInView.as_view('signin_view', account_service),
methods=['POST'])
app.add_url_rule("/user/social",
view_func=SignInSocialView.as_view('signin_social_view', account_service),
methods=['POST'])
error_handle(app)
아래와 같이 직접 코딩을 하면서 발생할 수 있는 에러들을 커스텀으로 직접 만들어 사용할 수 있게 틀을 짰다. 내가 만든 틀을 팀원이 잘 사용하는 것을 보니 괜히 뿌듯하다. (세형님의 도움도 감사합니다 😁)
'''
dev_error_message : 개발자 에러 메시지
error_message : 사용자 에러 메시지
class errorClassName(CustomUserError):
# parameter 설명
# 두 번째 인자 : user error message 세 번째 인자 : dev error message
def __init__(self, error_message, dev_error_message):
status_code = 500 # 에러코드
if not dev_error_message :
dev_error_message = "default error message"
super().__init__(status_code, dev_error_message, error_message)
'''
from flask import jsonify
from flask_request_validator import AbstractRule
from flask_request_validator.exceptions import RuleError, RequiredJsonKeyError, RequestError
class CustomUserError(Exception):
def __init__(self, status_code, dev_error_message, error_message):
self.status_code = status_code
self.dev_error_message = dev_error_message
self.error_message = error_message
class DatabaseCloseFail(CustomUserError):
def __init__(self, error_message, dev_error_message=None):
status_code = 500
if not dev_error_message:
dev_error_message = "database.close() error"
super().__init__(status_code, dev_error_message, error_message)
class TokenIsEmptyError(CustomUserError):
def __init__(self, error_message):
status_code = 400
dev_error_message = "token is empty"
super().__init__(status_code, dev_error_message, error_message)
class UserNotFoundError(CustomUserError):
def __init__(self, error_message):
status_code = 404
dev_error_message = "user not found"
super().__init__(status_code, dev_error_message, error_message)
class JwtInvalidSignatureError(CustomUserError):
def __init__(self, error_message):
status_code = 500
dev_error_message = "signature is damaged"
super().__init__(status_code, dev_error_message, error_message)
class JwtDecodeError(CustomUserError):
def __init__(self, error_message):
status_code = 500
dev_error_message = "token is damaged"
super().__init__(status_code, dev_error_message, error_message)
class MasterLoginRequired(CustomUserError):
def __init__(self, error_message):
status_code = 400
dev_error_message = "master login required"
super().__init__(status_code, dev_error_message, error_message)
class SellerLoginRequired(CustomUserError):
def __init__(self, error_message):
status_code = 400
dev_error_message = "seller login required"
class StartDateFail(CustomUserError):
def __init__(self,error_message):
status_code = 400
dev_error_message = "start_date gt end_date error"
super().__init__(status_code, dev_error_message, error_message)
class DataNotExists(CustomUserError):
def __init__(self, error_message, dev_error_message=None):
status_code = 500
if not dev_error_message:
dev_error_message = "order status type id doesn't exist"
class IsInt(AbstractRule):
def validate(self, value):
if not isinstance(value, int):
raise RuleError('invalid request')
return value
class IsStr(AbstractRule):
def validate(self, value):
if not isinstance(value, str):
raise RuleError('invalid request')
return value
class IsFloat(AbstractRule):
def validate(self, value):
if not isinstance(value, float):
raise RuleError('invalid request')
return value
class IsRequired(AbstractRule):
def validate(self, value):
if not value:
raise RuleError('invalid request')
return value
if not dev_error_message:
dev_error_message = "order status type id doesn't exist"
class SignUpFail(CustomUserError):
def __init__(self, error_message, dev_error_message=None):
status_code = 400
if not dev_error_message:
dev_error_message = "SignUpFail error"
super().__init__(status_code, dev_error_message, error_message)
class SignInError(CustomUserError):
def __init__(self, error_message, dev_error_message=None):
status_code = 400
if not dev_error_message:
dev_error_message = "SignInFaill error"
super().__init__(status_code, dev_error_message, error_message)
class TokenCreateError(CustomUserError):
def __init__(self, error_message, dev_error_message=None):
status_code = 400
if not dev_error_message:
dev_error_message = "TokenCreate error"
super().__init__(status_code, dev_error_message, error_message)
기본적으로 CustomUserErrpr
상속받아서 사용한다.
커스텀으로 만든 error 클래스를
raise
를 사용해서error_handle
로 올린다.
오 잘 쓰겠습니다!