def decorator(original_func):
def inner(*args, **kwargs):
return original_func(*args, **kwargs)
return inner
@decorator
def origin(x, y):
return x + y
origin("Hello", "World")
# Hello World
데코레이터는 본 함수가 실행 되기 전, 미리 생성된 함수를 실행하므로 효율적인 코드 재활용에 큰 도움이 된다. 상상해 보자 만약 어떤 사람이 회원가입을 하고 게시글을 보고 댓글을 쓰고 좋아요를 누를 때마다 사용자의 로그인 상태에 대해 서버는 알 수 없는 stateless 상태이기에 해당 로직에서 매번 사용자의 로그인의 상황을 체크하는 코드를 로직에 포함 시켜 놓아야 한다. 그러나 재사용에 유리한 Decorator를 이용한다면 매번 사용자의 상태를 확인하는 코드를 포함 시킬 필요가 없이 데코레이터를 통해 해당 사용자의 접근 권한에 대해 쉽게 판별할 수 있다.
jwt.exceptions.DecodeError 또한 None 타입 자료를 decode 할 때, 발생하는 에러를 잡기 위함이다.User.DoesNotExist except로 잡아준다.def login_decorator(func):
def wrapper(self, request, *args, **kwargs):
try:
auth_token = request.headers.get('Authorization', None)
payload = jwt.decode(auth_token, SECRET_KEY, algorithm='HS256')
request.user = User.objects.get(id=payload['id'])
return func(self, request, *args, **kwargs)
except jwt.exceptions.DecodeError:
return JsonResponse({'message':'INVALID_TOKEN'}, status=401)
except User.DoesNotExist:
return JsonResponse({'message':'INVALID_USER'}, status=403)
return wrapper
첫 번째 방법과 같은 방법이지만 try, except가 아닌 나올 수 있는 에러에 해당되는 if문으로 에러를 잡는다.
INVALID_TOKEN를 리턴한다.UNKNOWN_USER를 리턴한다.request.user로 해당 db row를 담고, 본 함수를 호출한다.def login_decorator(func):
def wrapper(self, request, *args, **kwargs):
if not 'Authorization' in request.headers:
return JsonResponse({'message':'INVALID_TOKEN'}, status=401)
payload = jwt.decode(request.headers['Authorization']), SECRET_KEY, alogorithm='HS256')
if not User.objects.filter(id=payload['id']):
return JsonResponse({'message':'UNKNOWN_USER'}, status=40
request.user = User.objects.get(id=payload['id'])
return func(self, request, *args, **kwargs)
이번 로그인 데코레이터 실습을 통해 얻은 것은 백엔드 개발자는 '서버가 절대 죽지 않도록 적절한 리턴 값을 프론트(클라이언트)에게 전달해 줘야 한다' 라는 말에 대한 답을 얻은 것 같다. 그 만큼 내가 쓴 코드에 어떤 에러가 나올 지 지금의 나는 예측하기 쉽지 않다. 그렇기에 더 더욱 코드를 치는 중간 중간에 에러를 확인하고 어떻게 에러를 잡을 지 고민해 보는 것이 중요한 것 같다.