API 구현
회고록
이전 과제에서 회원가입과 로그인을 구현해 본적이 있어서 어렵지 않게 구현을 했던거 같다.
하지만 아쉬웠던 점은 이전 과제와 동일하게 구현을 해서 새롭게 뭔가를 한거 같지가 않은거 같다는 점이다.
획일화된 코드가 아닌 새로운 코드를 작성하는게 맞는지, 아니면 가능하면 같은 코드를 사용하는게 맞는지 의문이 든다.
아마 모든 홈페이지에 동일한 기능이 있다면, 그 기능에 대한 동일한 코드가 있을 것이고, 그렇다면 복사 붙혀넣기를 하면 기능이 구현되는데, 굳이 이 부분을 알 필요가 있는 것일까?라는 생각이 들었다.
다른 한편으로는 홈페이지 마다 기능은 같지만, 기능에 부가적인 특징이 다르므로 새로 만드는게 맞다는 생각이 들기도 한다.
이미 수많은 기능이 있을 것이고, 그에 대해 조금씩 부가적으로 추가해가는 것이 API를 구현하는 것이라는 생각이 든다.
core/utils.py
import jwt
import re
from django.conf import settings
from django.http import JsonResponse
from users.models import User
def check_username(username):
REGEX_USERNAME = "^[A-Za-z0-9]{4,12}$"
if not re.match(REGEX_USERNAME, username):
raise ValueError("INVALID_USERNAME_FORMAT")
def check_password(password):
REGEX_PASSWORD = '^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,}$'
if not re.match(REGEX_PASSWORD, password):
raise ValueError("INVALID_PASSWORD_FORMAT")
def check_email(email):
REGEX_EMAIL = '^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
if not re.match(REGEX_EMAIL, email):
raise ValueError("INVALID_EMAIL_FORMAT")
def check_phone_number(phone_number):
REGEX_PHONE_NUMBER = '^\d{3}-\d{3,4}-\d{4}$'
if not re.match(REGEX_PHONE_NUMBER, phone_number ):
raise ValueError("INVALID_PHONE_NUMBER_FORMAT")
def duplicate_check_username(username):
if User.objects.filter(username = username).exists():
raise ValueError("INVILD_USERNAME")
def duplicate_check_email(email):
if User.objects.filter(email = email).exists():
raise ValueError("INVAILD_EMAIL")
def duplicate_check_phone_number(phone_number):
if User.objects.filter(phone_number = phone_number).exists():
raise ValueError("INVAILD_PHONE_NUMBER")
def login_decorator(func):
def wrapper(self, request, *args, **kwargs):
try:
access_token = request.headers.get('Authorization')
payload = jwt.decode(access_token, settings.SECRET_KEY, settings.ALGORITHM)
user = User.objects.get(id = payload['id'])
request.user = user
return func(self, request, *args, **kwargs)
except jwt.exceptions.DecodeError:
return JsonResponse({'MESSAGE': 'INVALID_TOKEN'}, status= 400)
except User.DoesNotExist:
return JsonResponse({'MESSAGE': 'INVALID_USER'}, status=400)
return wrapper
회원가입 API
class SignUpView(View):
def post(self, request):
try:
data = json.loads(request.body)
name = data["name"]
username = data["username"]
password = data["password"]
address = data["address"]
email = data["email"]
phone_number = data["phone_number"]
check_username(username)
check_password(password)
check_phone_number(phone_number)
check_email(email)
duplicate_check_username(username)
duplicate_check_email(email)
duplicate_check_phone_number(phone_number)
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
User.objects.create(
name = name,
username = username,
password = hashed_password,
address = address,
email = email,
phone_number = phone_number
)
return JsonResponse({"MESSAGE": "SUCCESS"}, status=200)
except KeyError:
return JsonResponse({"MESSAGE":"KEY_ERROR"}, status=400)
except ValueError as e :
return JsonResponse({"MESSAGE": f"{e}"}, status=400)
로그인 API
class SignInView(View):
def post(self, request):
try:
data = json.loads(request.body)
user = User.objects.get(username = data['username'])
hashed_password = user.password.encode('utf-8')
if not bcrypt.checkpw(data['password'].encode('utf-8'), hashed_password):
return JsonResponse({"MESSAGE":"INVALID_USER"}, status=400)
access_token = jwt.encode({'id' : user.id}, settings.SECRET_KEY, settings.ALGORITHM)
return JsonResponse(
{"MESSAGE" : "LOGIN SUCCESS",
"ACCESS_TOKEN" : access_token},
status= 200
)
except KeyError:
return JsonResponse({"MESSAGE":"KEY_ERROR"},status=400)
except User.DoesNotExist:
return JsonResponse({"MESSAGE" :"DOESNOTEXIST"}, status=400)