1차 프로젝트가 끝나고 바로 2차 프로젝트가 시작되었다. 1차에선 프런트 3 백 2(코로나로 인해 반이 지나고 다른 팀원이 합류) 총 5명의 팀으로 프로젝트가 진행되었고 2차에선 프런트 4 백 3, 총 7명이 팀이 되어 프로젝트를 진행하게 되었다. 인원수가 거의 전에 비해 2배가 되었고, 특히 백엔드가 총 3명이 되면서 그전과는 조금 다른 느낌(?)의 프로젝트가 될 것 같았다.
이번에는 영화예매사이트를 만들어보기로 하였고 그중 CGV를 모델링하여 우리만의 페이지를 만들어보려고 했다.
위와 같이 cgv의 예매사이트는 너무 복잡해보였지 때문에 조금은 다른 예매 페이지를 구상하였고 먼저 영화를 선택했을 때 그에 해당하는 정보들을 선택할 수 있게끔 하려 했다.
팀원들의 공통된 의견으로 보통 영화를 예매하러 들어오면 영화는 어느 정도 선택을 해놓고 날짜나 시간을 정한다라는 것이었다. 그래서 위와 같이 영화를 선택한 후에 필요한 정보들을 고객들이 편리하게 이용할 수 있게 좀 더 직관적으로 꾸며보려 한 것이다.
처음에 어떤 API를 만들어야 할지 계획을 짜려하는데 너무나 어렵고 헷갈렸던 기억이 난다. 어떤 정보를 보내줘야 하고 어떤 정보는 안보 내줘도 되는지 정하는 게 헷갈렸었다. 특히 날짜를 선택하기 위한 달력의 정보는 프런트엔드에서 달력 라이브러리를 사용한다고 했기에 헷갈림이 가중된 것 같았다
결론적으로 달력 빼고 지역/영화관정보와 시간정보를 보내주기로 하였다.
먼저 지역과 영화관정보는 배열 안에 객체를 담아서 보내기로 했고, 프런트에서는 그 정보를 받아 위에화 같이 보여주기로 했다.
[
{
"region_id": 1,
"name": "서울",
"location": [
{
"branch_id": 1,
"branch_name": "강남"
},
{
"branch_id": 2,
"branch_name": "강변"
}
]
},
{
"region_id": 2,
"name": "경기",
"location": [
{
"branch_id": 3,
"branch_name": "경기광주"
},
{
"branch_id": 4,
"branch_name": "고양행신"
}
]
},
{
"region_id": 3,
"name": "인천",
"location": [
{
"branch_id": 5,
"branch_name": "계양"
},
{
"branch_id": 6,
"branch_name": "부평"
}
]
}
]
사실 처음 예매페이지를 계획할 때 엄청난 filtering이 들어가야 한다고 생각해서 1차 프로젝트 때 사용했던 Query Builder를 사용하려 했다. 영화를 선택하고 영화관, 날짜를 선택하면 해당되는 시간정보가 나타나는?
하지만 영화와 영화관을 선택했을 때 해당영화관에 선택된 영화가 매일매일 상영되는 것은 아니었다.
😳❓
1차 프로젝트에서 query parameter를 사용해서 하나의 endpoint로 filtering 등 모든 것들을 처리하는 부분을 완성해서 만족스러웠는지, 이번에도 똑같은 방식으로 하려 했던 것 같다.
기존에 사용한 방법으로만 생각하려 했어서 그랬는지 당최 어떤 api를 어떻게 만들어야 할지 감이 잡히지 않았다. 이 부분을 멘토님과 이야기해 보았고 “여러 개의 api를 만들어서 처리하면 되지 않을까요?”라는 말이 100% 이해되지 않았지만 일단 여러개의 api를 사용해서 어떻게 하면 예매페이지를 처리할 수 있을까 고민했다.
첫 번째, 영화를 선택해서 예매페이지에 들어오게 되었을 때 영화관을 선택하면 해당영화관에 대한 id값을 받아서 해당 지점에서 선택된 영화를 상영하는 날짜와 시간정보를 보내주는 API를 만들었다.
[
{
"id": 5,
"name": "2022. 12. 5",
"time": [
{
"time": "20:00",
"time_id": 2
}
]
},
{
"id": 6,
"name": "2022. 12. 6",
"time": [
{
"time": "8:00",
"time_id": 1
}
]
}
]
위와 같은 데이터 형식으로 데이터를 보내면 front에서는 해당 날짜를 선택했을 때는 시간정보를 보여주고 그외 날짜를 선택했을때는 아무런 시간정보를 주지 않게 된다.
(사실, 처음부터 맡게 된 API가 아니었기에 충분히 생각하고 API를 만들지 못했다. 프로젝트 중간에 팀원의 요청으로 맡게 된 거라 프로젝트가 돌아가게끔 하기 위해서 상황에 맞춰서 주먹구구식으로 만들었던 내용들도 있다..)
소셜 로그인 API - 카카오
전 프로젝트에서는 JWT와 BCRYPT를 이용한 로그인/회원가입을 구현했었다면 이번에는 다른 방식으로 인증/인가 방법을 바꿔보려 했다. 그중에 선택한 것이 모든 웹사이트에서 요즘은 대부분 제공하는 소셜 로그인을 통한 회원가입 및 로그인이었다. 그중 가장 접근에 대한 허들을 낮출 수 있는 카카오 소셜 로그인 API를 사용하였다.
특히 OAuth를 통해 인증을 하게 되는데 그렇게 되면 보안이 약할 것 같은 작은 회사들이 제공하는 웹사이트에 대한 신뢰성 부족 문제를 보완할 수 있고 접근에 대한 허들을 낮출 수 있기에 서비스적인 측면으로 보았을 때 매우 효과적일 것이라고 생각했다.
1. 토큰 요청
- 프런트에서 인가코드를 redirect_url로 전달받은 인가코드를 BE로 전달해 주면 그 코드를 이용하여 Kakao Auth Server에 토큰 요청을 한다.
const signinWithKakao = async (code) => {
const requestTokenToKakao = {
method: "post",
url: "<https://kauth.kakao.com/oauth/token>",
headers: {
"Content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
data: {
client_id: process.env.REST_API_KEY,
code: code,
grant_type: "authorization_code",
redirect_uri: process.env.REDIRECT_URI,
},
};
const response = await axios(
requestTokenToKakao,
{},
{
withCredentials: true,
}
).then((response) => response.data);
...이하 생략
}
const signinWithKakao = async (code) => {
const requestTokenToKakao = {
method: "post",
url: "<https://kauth.kakao.com/oauth/token>",
headers: {
"Content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
data: qs.stringify({
client_id: process.env.REST_API_KEY,
code: code,
grant_type: "authorization_code",
redirect_uri: process.env.REDIRECT_URI,
}),
};
const response = await axios(
requestTokenToKakao,
{},
{
withCredentials: true,
}
).then((response) => response.data);
const axiosRequest = {
method: "GET",
url: "<https://kapi.kakao.com/v2/user/me>",
headers: {
Authorization: `Bearer ${response.access_token}`,
},
};
const getKakaoUserInfo = await axios(axiosRequest, {
withCredentials: true,
});
const { id } = getKakaoUserInfo.data;
const { profile, email } = getKakaoUserInfo.data.kakao_account;
const emailCheck = await userDao.getUserbyEmail(email);
let flag = false;
let info;
if (!emailCheck) {
const result = await userDao.createUser(profile.nickname, email, id);
info = await userDao.getUserInfoByUserId(result.insertId);
flag = true;
}
const user = await userDao.getUserBySocialId(id);
const jwtToken = jwt.sign({ id: user.social_id }, process.env.JWT_SECRET_KEY, {
expiresIn: "1d",
});
return { jwtToken, flag, info };
'프로젝트' 카테고리의 다른 글
[인턴쉽] 회고 - 협업 (0) | 2023.02.27 |
---|---|
[2차 프로젝트] 회고 - 4L (0) | 2023.02.27 |
[2차 프로젝트]회고 - 협업 (0) | 2023.02.27 |
[1차 프로젝트] 회고 - KPT (0) | 2023.02.27 |
[1차 프로젝트] 회고 - 기능 (0) | 2023.02.26 |