데브코스 웹풀스택 과정/TIL
0924 로그인 처리 및 고도화, 자바스크립트 Object.keys(), 채널 API 설계구현
thinktank911
2025. 9. 24. 15:56
로그인 기본 로직
- req.body 안에서 구조분해 할당으로 userId, pwd, name 꺼내기
- db foreach문 돌려서 db value값의 userId와 req.body에서 보내 온 userId를 비교
- hasUserId 변수를 false 처리 한 다음 db의 userId와 요청 userId가 같은 경우 true로 변경
- userId를 찾으면 db 패스워드와 요청 패스워드도 비교한다.
- 패스워드가 일치하면 200 코드 보내주고 name 출력
- 일치하지 않으면 404 코드 보내주고 message 출력
const loginInfo = req.body;
console.log(loginInfo); // userId, pwd
// userId가 DB에 저장된 회원인지 확인
const {userId, pwd, name} = loginInfo
var hasUserId = false;
db.forEach((user, id)=>{
// a : 데이터, value
// b : 인덱스, key
// c : 전체 객체, Map
if(user.userId === userId){
hasUserId = true;
// pwd도 맞는지 비교
if(user.pwd === pwd){
res.status(200).json({
message : `${name}님 환영합니다.`
})
}else{
res.status(404).json({
message : "비밀번호가 일치하지 않습니다."
})
}
}
})
if(hasUserId){
console.log("찾았다");
}
// userId 값을 못 찾았으면
else{
res.status(404).json({
message : "없는 아이디입니다."
})
}
로그인 예외 처리
- 패스워드 비교 구문 또한 hasUserId 조건 구문으로 빼주려 한다.
이때, user.userId에서 user는 forEach문 안에서만 쓸 수 있는 변수로 밖으로 뺄 수가 없다. - loginUser라는 객체 변수를 만들어 forEach문에서 조건값이 맞는 user 데이터를 loginUser에 넣는다.
- 그러면 패스워드 비교 구문을 forEach문 밖으로 빼내서 hasUserId if문으로 이동할 수 있다.
var hasUserId = false;
var logInUser = {}
db.forEach((user, id)=>{
// a : 데이터, value
// b : 인덱스, key
// c : 전체 객체, Map
if(user.userId === userId){
hasUserId = true;
logInUser = user; // 찾은 user 변수에 넣기
}
})
if(hasUserId){
console.log("찾았다");
// pwd도 맞는지 비교
if(logInUser.pwd === pwd){
res.status(200).json({
message : `${name}님 환영합니다.`
})
}else{
res.status(404).json({
message : "비밀번호가 일치하지 않습니다."
})
}
}
- hasUserId로 조건을 걸지 않고, loginUser로 조건을 걸어도 충분할 것 같다.
- hasUserId 자리에 loginUser로 대체
var logInUser = {}
db.forEach((user, id)=>{
// a : 데이터, value
// b : 인덱스, key
// c : 전체 객체, Map
if(user.userId === userId){
logInUser = user; // 찾은 user 변수에 넣기
}
})
if(logInUser){
console.log("찾았다");
- 이때 loginUser는 빈 객체로서 if(loginUser) 시 객체가 비었음에도 true값이 된다.
- 이에 빈 객체를 확인하는 방법을 알아봤다.
자바스크립트 Object.keys()
* 빈 객체 확인하는 방법 3가지 : {}
- 객체.keys()
- for
- lodash(라이브러리) : isEmpty
- Object.keys() 활용하여 isEmpty 함수 만들어서 사용해볼 수 있다.
=> 유지보수성에도 좋음. 다른 사람 이해 가능하도록 함수명 지어서 확인할 수 있으니 가독성 좋다. - 주의 사항 : 객체인지 먼저 확인이 필요하다.
if(obj.constructor === Object)
로그인 고도화
- 객체 값이 존재하는지 확인하는 함수를 분리해서 조건문에 사용
- 함수명 : isEmpty() => isExist()로 긍정문 사용 (클린코드 관점)
// 객체 값 존재하는지 확인 함수
function isExist(obj){
if(Object.keys(obj).length){
return true;
}else{
return false;
}
}
if(isExist(loginUser)){
console.log("찾았다");
// pwd도 맞는지 비교
if(loginUser.pwd === pwd){
res.status(200).json({
message : `${name}님 환영합니다.`
})
}else{
res.status(404).json({
message : "비밀번호가 일치하지 않습니다."
})
}
}
채널 API 설계 1탄 - API 명세
- 설계 목표 : URL, http method/status, req/res
회원은 계정 1개당 채널 100개를 가질 수 있다.
채널
- 채널생성
- 채널수정
- 채널삭제
1) 채널 생성 : POST /channels
- req : body(channelTitle)
- res 201 :
${channelTitle}님 채널을 응원합니다.
=> 다른 페이지 띄워주고 싶어 ex. 채널관리 페이지
2) 채널 개별 수정 : PUT /channels/:id
- req : URL(id), body(channelTitle)
- res 200 :
채널명이 성공적으로 수정되었습니다. 기존 : ${} => 수정 : ${}
3) 채널 개별 삭제 : DELETE /channels/:id
- req : URL(id)
- res 200 : 채널이 삭제되었습니다. => 메인페이지 이동
4) 채널 전체 조회 : GET /channels
- req : x
- res 200 : 채널 전체 데이터 list, json array
5) 채널 개별 조회 : GET /channels/:id
- req : URL(id)
- res 200 : 채널 개별 데이터 -> channelTitle
채널 API 설계 2탄 - 화면 설계
채널 생성 페이지
- 채널 생성 버튼 클릭 시 => 입력받은 채널명을 받아서 채널 생성(등록) API
채널 관리 페이지(마이페이지 안에 버튼 존재)
- 생성/수정/삭제 버튼 존재
(1) 화면 출력 => 이 회원이 소유한 전체 채널 조회 API
(2) 삭제 버튼 클릭 시 => 개별 채널 삭제 API
개별 채널 수정 페이지
(1) 기존 개별 채널 정보 조회 API
(2) 수정완료 버튼 클릭 시 => 개별 채널 수정 API
채널 API 코드 틀 route
- route로 중복 url 합치기
- 전체 조회/개별 생성 => '/channels'로 합치기
- 개별 조회/개별 수정/개별 삭제 =>'/channels/:id'로 합치기
app
.route('/channels')
.get() // 채널 전체 조회
.post() // 채널 개별 생성
app
.route('/channels/:id')
.get() // 채널 개별 조회
.put() // 채널 개별 수정
.delete() // 채널 개별 삭제
채널 생성, 채널 개별 조회
채널개별조회
<이슈>
TypeError: Assignment to constant variable. 는 간단히 말해서 const 로 선언한 변수에 재할당을 시도했을 때 발생하는 오류
- 채널 개별 조회 시 위 에러가 났는데 const 변수를 재할당해줘서 생기는 문제였다. 생각보다 자주 나는 에러라 기억을 해둘 필요가 있다.
- const를 let으로 변경하니 에러 해결
// 변경 전
const {id} = req.params;
id = parseInt(id);
// 변경 후
let {id} = req.params;
id = parseInt(id);
채널개별생성
<이슈>
Cannot read properties of undefined (reading 'channelTitle')
- 예외처리를 확인하기 위해 req.body값을 지우고 post 요청을 보냈는데 서버(500)에러가 났다.
- 예외처리 해줬는데 왜 서버 에러가 나는건지 궁금했다.
// 변경 전
.post((req,res)=>{
if(req.body.channelTitle){
// db 등록
db.set(id++, req.body);
res.status(201).json({
message : `${db.get(id-1).channelTitle} 채널이 생성되었습니다.`
})
}
else{
res.status(400).json({
message : "입력 값을 다시 확인해주세요."
})
}
- if (req.body.channelTitle) 처리했는데 req.body 가 아예 없는 경우에는 그 줄에서 터진다.
- 조건문을 req.body 존재 여부부터 확인하도록 req.body를 넣어주니 잘 되었다.
- body값을 아예 비워버리면 json 파싱부터 실패하므로 req.body가 없으면 {} 객체로 대체해서 보내주도록 처리하는 방법도 있다.
// 변경 후
post((req,res)=>{
if(req.body && req.body.channelTitle){
// db 등록
db.set(id++, req.body);
채널 개별 삭제, 개별 수정
채널개별수정
.put((req,res)=>{
let {id} = req.params;
id = parseInt(id);
const channel = db.get(id); // db에서 채널 찾기
var oldTitle = channel.channelTitle; // db 채널 old타이틀 변수 보관
if(req.body && channel){
var newTitle = req.body.channelTitle; // req.body에서 new타이틀 보관
channel.channelTitle = newTitle;
// db에 덮어쓰기
db.set(id, channel);
res.status(200).json({
message : `${oldTitle} -> ${newTitle} 으로 수정되었습니다.`
})
}
else{
res.status(404).json({
message : "존재하지 않는 채널입니다."
})
}
}) // 채널 개별 수정
<이슈>
db is not a function
- put 요청 시 에러
- 오타 : db(id, channel) => db.set(id, channel)
채널 전체 조회
- ` var channels = [] ` (json array) : json을 배열 형태로 보낸다.
- channels가 배열이므로 값을 넣어줄 때 channels.pusth(value)로 넣어줄 수 있다.
.get((req,res)=>{
// json array(여러개 json의 배열) 로 보내기
var channels = []
if(db.size !== 0){
db.forEach((value, key) => {
channels.push(value)
})
// 꺼낼 때 channels[0]
res.status(200).json(channels)
} else{
res.status(404).json({
message : "채널이 존재하지 않습니다."
})
}
}) // 채널 전체 조회
Object.keys()관련하여 깊이 공부해보고 싶어서 map, object, json을 비교해봤었는데 잘한 선택이었다. 본격적으로 API 설계하고 구현하는 과정에서 에러가 나기 시작하는데 평소에는 그냥 에러가 해결되면 넘기다가 블로그를 쓰기 시작하면서 정리를 하기 시작하니 좀 더 공부가 되는 느낌이다. 좋은 변화다.
흥미로웠던 지점은 함수명을 지을 때 isEmpty()를 관념적으로 많이 썼기에 그냥 넘어갔었는데 긍정문이 가독성이 좋기 때문에 클린코드 관점에서 isExist()로 고쳤던 게 인상적이었다. 의문이 가는 지점은 자바에선 isEmpty() 함수가 따로 있는 걸로 알고 있는데 자바를 아는 사람의 관점에선 isEmpty()로 명명하는 편이 좀 더 이해하기 편하지 않을까 하는 생각을 했다.