<백엔드>
- 유저 정보 조회
- 내가 맡은 부분이 다른 기능이 구현되어야 할 수 있는 거라서 기다리면서 프론트엔드 html을 만들고 있었다
- 로그인, 회원가입 기능이 추가되니 바로 js도 연결하고 싶어서 그걸 하다가 로그인 했을 때 헤더에 유저 닉네임을 넣고 싶어졌다
- 근데 백엔드에 현재 유저 정보 조회가 구현되어 있지 않은데 이 부분 담당한 팀원분이 코드 짤 수 없는 상태여서 내가 대신 짰다
- 간단한 거라 코드 짜면서 별다른 에러는 없었다
# users/urls.py
from django.urls import path
from users import views
urlpatterns = [
...
path("profile/<int:user_id>/", views.ProfileView.as_view(), name="profile_view"),
...
]
# users/views.py
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.generics import get_object_or_404
from users.models import User
from users.serializers import UserSerializer
class ProfileView(APIView):
def get(self, request, user_id):
"""유저 프로필 조회"""
user = get_object_or_404(User, id=user_id)
serializer = UserSerializer(user)
return Response(serializer.data, status=status.HTTP_200_OK)
- 테스트코드
- 지난 프로젝트 때 테스트코드를 짜고 싶었는데 시간이 없어서 못 짰다
- 발표하고 나서 피드백으로 테스트코드를 추가하면 좋겠다는 얘기를 들었다
- 이번 프로젝트 때는 테스트코드를 짜겠다는 일념 하에 내가 테스트코드를 도맡아서 짜기로 했다
회원가입
# users/tests.py
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
class UserRegistrationTest(APITestCase):
"""회원가입 테스트"""
def test_registration_201(self):
"""return 201 Created"""
url = reverse("user_view")
user_data = {
"email":"test@test.test",
"password":"1234",
"nickname":"test",
"age":"10",
"gender":"F"
}
response = self.client.post(url, user_data)
self.assertEqual(response.status_code, 201)
def test_registration_400(self):
"""return 400 Bad Request
400 나오는 경우 :
email 형식으로 쓰지 않았을 때, age 외에 다른 필드 중 하나라도 작성하지 않았을 때
"""
url = reverse("user_view")
user_data = {
"email":"test",
"password":"1234",
"nickname":"test",
"age":"10", # null = True
"gender":"F"
}
response = self.client.post(url, user_data)
self.assertEqual(response.status_code, 400)
- 전에 들었던 테스트 코드 강의를 참조해서 했더니 별다른 문제는 없었다
로그인
# users/tests.py
...
from users.models import User
...
class UserTest(APITestCase):
def setUp(self):
"""유저 미리 만들기"""
self.data = {"email": "test@test.test", "nickname":"test", "password": "1234"}
self.user = User.objects.create_user("test@test.test", "test", "1234")
def test_get_user_data(self):
"""유저 프로필 조회 테스트"""
url = self.user.get_absolute_url()
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["email"], self.data["email"])
- 이 코드는 짤 때 문제가 있었는데 지금 아까 문제상황으로 돌려놨는데도 문제가 없다..?
- 이게 무슨 일인지..? 아깐 왜 문제가 있었던 건지..
<프론트엔드>
- 헤더 만들기
<!-- navbar.html -->
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<div class="collapse navbar-collapse justify-content-start">
<ul class="navbar-nav mr-auto" id="navbar-left">
<li class="nav-item">
<a class="nav-link" href="#">띵곡맛집</a>
</li>
</ul>
</div>
<div class="nav justify-content-center">
<a class="navbar-brand" href="#">
<img src="/static/image/free-icon-music-6599985.png" width="35" height="35" alt="">
</a>
</div>
<div class="collapse navbar-collapse justify-content-end">
<ul class="navbar-nav ml-auto" id="navbar-right">
<li class="nav-item">
<a class="nav-link" id="login-button" href="/users/login.html">로그인</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/" id="intro"></a>
</li>
</ul>
</div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-right"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
</body>
- 부트스트랩 네비게이션바를 이용해 만들었다
- 비로그인 상태에서는 이렇게 보인다
- 회원가입 연결
// api.js
// 회원가입(인풋박스에 담긴 정보 백엔드로 request 보내기)
async function handleSignin() {
const email = document.getElementById("email").value
const password = document.getElementById("password").value
const nickname = document.getElementById("nickname").value
const gender = document.getElementById("gender").value
const age = document.getElementById("age").value
const response = await fetch(`${backend_base_url}/api/users/signup/`, {
headers: {
'content-type': 'application/json'
},
method: 'POST',
body: JSON.stringify({
"email": email,
"password": password,
"nickname": nickname,
"gender": gender,
"age": age,
})
})
return response
}
// signup.js
// 회원가입 폼 다 쓰고 가입하기 눌렀을 때 실행되는 함수
async function handleSignupBtn() {
const response = await handleSignin();
if (response.status == 201) {
alert("회원가입을 축하합니다!")
window.location.replace(`${frontend_base_url}/users/login.html`)
} else if (response.status == 400) {
alert("값을 제대로 입력해 주십시오")
} else {
alert(`${response.statusText}`)
}
}
- 이것도 전에 했던 거라 별다른 에러는 없었다
- password check는 기획 단계에선 있었는데 회원가입 구현하신 팀원분이 안 넣으셔서 일단 주석처리 해놨다
- 내일 얘기해 볼 예정
- 로그인 연결
// api.js
// 로그인
async function handleLogin() {
const email = document.getElementById("email").value
const password = document.getElementById("password").value
const response = await fetch(`${backend_base_url}/api/users/login/`, {
headers: {
'content-type': 'application/json'
},
method: 'POST',
body: JSON.stringify({
"email": email,
"password": password
})
})
return response
}
// login.js
// 로그인 폼 다 쓰고 로그인 눌렀을 때 실행되는 함수
async function handleLoginBtn() {
const response = await handleLogin();
if (response.status == 200) {
const response_json = await response.json()
localStorage.setItem("access", response_json.access);
localStorage.setItem("refresh", response_json.refresh);
const base64Url = response_json.access.split('.')[1];
const base64 = base64Url.replace(/-/g, '+');
const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
localStorage.setItem("payload", jsonPayload)
alert("환영합니다!")
window.location.replace(`${frontend_base_url}/`)
} else {
alert("회원정보가 일치하지 않습니다!")
}
}
- 로그인 하면 바뀌는 헤더
- 저기 gu1이 닉네임인데 저 정보를 가져와야 해서 백엔드에서 유저 정보 조회하는 함수를 만든 것이다
- 근데 유저 정보 조회하는 함수는 내일 다시 고민해 봐야 할 것 같아서 블로그엔 아직 안 적겠다
- 지금은 payload에서 user_id를 가져오는 식으로 되어 있는데 그러면 다른 유저 정보는 가져올 수가 없다
- 백엔드에서는 user_id만 있으면 다른 유저의 정보가 조회되는 식으로 되어 있는데 프론트엔드에서 다른 유저의 id를 어떻게 하면 가져올 수 있는지 알아봐야 한다...
- 로그아웃
// api.js
// 로그아웃
function handleLogout() {
localStorage.removeItem("access")
localStorage.removeItem("refresh")
localStorage.removeItem("payload")
window.location.replace(`${frontend_base_url}/`)
}
- 로그아웃은 토큰만 삭제하면 되는거라 백엔드에는 구현할 필요가 없고 이렇게 간단하게 로그아웃 할 수 있다