2024년 9월 10일
: Node.js에서의 라우팅은 request(요청)가 날아왔을 때, 원하는 경로에 따라 적절한 방향으로 경로를 안내해주는 것이다.
// app.js
// 서버 역할
const express = require('express');
const app = express();
app.listen(7777);
const userRouter = require('./routes/user-demo');
app.use("/", userRouter)
// 미들웨어처럼 사용하겠다는 의미
// routes / user-demo.js
const express = require('express');
const router = express.Router();
// express의 라우터 사용
// app -> router 로 모두 바꾸기
router.use(express.json());
.
.
.
// 코드 생략
module.exports = router;
POSTMAN) POST + localhost:7777/join + (raw body) {”userId” : “userId1”, “password” : 1234, “name” : “user1”}
❗️ app.js에서 서버를 구동시켜야함
이제 channel-demo도 연결시켜보자.
// routes / channel-demo.js
const express = require('express');
const router = express.Router();
router.use(express.json());
// 마찬가지로 app -> router로 모두 바꾸기
// refactoring -> F2 눌러서 app => router로 모두 쉽게 바꾸기
// 변수 선언문을 바꿔야 다 바꿀수 있음
router
.route('/channels')
.
.
.
// 코드 생략
module.exports = router;
// app.js
const express = require('express');
const app = express();
app.listen(7777);
const userRouter = require('./routes/user-demo');
const channelRouter = require('./routes/channel-demo');
app.use("/", userRouter);
app.use("/", channelRouter);
POSTMAN) POST + localhost:7777/channels + (raw body) { “channelTitle” : “쨍순이” }
❗️ API가 나타내고 싶은 객체는 복수형이기 때문에 모듈 이름을 바꿔주는 것이 좋다 -> 파일 이름 바꾸기 : user-demo.js -> users.js / channel-demo.js -> channels.js
❗️ 공통된 url 빼기
- users의 url은 통일 된 url이 없기 때문에 공통 url을 뺄 수 없다
- channels는 공통된 url로 이루어져 있으므로 뺄 수 있음
// app.js
const express = require('express');
const app = express();
app.listen(7777);
const userRouter = require('./routes/users');
const channelRouter = require('./routes/channels');
app.use("/", userRouter)
app.use("/channels", channelRouter)
// routes / channels.js
const express = require('express');
const router = express.Router();
router.use(express.json());
router
.route('/')
.
.
.
.route('/:id')
// 코드 생략
: 데이터베이스를 고민해봐야함
따라서, ERD를 그려보면서 데이터를 고민 해봐야 한다
ERD를 보았을 때, 회원은 채널에 대한 관계를 모르고, 채널은 어떤 회원이 있는지 알 수 있음 -> 채널이 회원에 대한 정보 접근 가능
강사님과 ERD를 그려보면서 API를 설계할 때 ERD를 먼저 설계해보고 API를 설계하거나 다시 수정해야하는 것을 알게 되었다. ERD 그리는 것을 좀 연습해봐야겠다.
: 처음 채널에 대한 API를 설계 했을 때 우리는,
채널 생성
${channelTitle}님 채널이 만들어졌어요!
채널 전체 조회
채널 전체 데이터(list)
이렇게 설계 했었다. 하지만 ERD를 그려보면서, id가 아닌 userId를 이용해 회원을 구분해야 하므로 설계를 수정해야한다.
그리고 실제로는 userId값을 body로 받지 않고, header에 숨겨서 token을 이용해 받아온다고 한다. 지금은 실제가 아니니(나중에 실제로 연습한다고 하셨음!) body에 담아서 channelTitle과 userId를 받아 올 것이다.
따라서, API 설계를 수정하자면
${channelTitle}님 채널이 만들어졌어요!
: 채널 생성은 사실 수정할게 없다. 왜냐하면 userId만 추가해서 request에 던져줄 예정(값만 받으면 됨)
// channels.js
router
.route('/')
.post((res, res) => {
if (req.body.channelTitle) {
let channel = req.body
db.set(id++, channel)
res.status(201).json({
message : `${db.get(id-1).channelTitle}님 환영해요!`
})
} else {
res.status(400).json({
meesage : `요청 값을 다시 보내주세요`
})
}
})
POSTMAN)
회원 가입 ⇒ POST + localhost:7777/join + (raw body) {”userId” : ”userId1”, “password” : 1234, “name” : “user1”} 하고,
채널 등록 ⇒ POST + localhost:7777/channels + (raw body) {”channelTitle” : “쨍순이”, “userId” : “userId1”} 하고 send 처리 하면 만들어졌다는 메시지 나옴
채널 개별 조회 ⇒ GET + localhost:7777/channels/1 ⇒ {”channelTitle” : “쨍순이”, “userId” : “userId1”} 나오는 것 확인
그럼 만약, 존재하지 않는 userId를 채널 생성에 넣으면 어떨까?
: 등록하지 않은 userId로 채널이 생성된다. 이렇게 되면, 나중에 map를 이용해서 다 비교해줘야 한다고 하시는데.. 무튼 이건 나중에 살펴볼 예정이고,
지금은 존재하는 userId만 넣어서 조회할 예정.
: 한 회원의 전체 채널들을 조회하는 코드를 수정해보자.
먼저, userId값을 확인해서 조회시키기
// channels.js
router
.route('/')
.get((req res) => {
if(db.size) {
const {userId} = req.body;
let channels = [];
db.forEach(function(value, key) {
// value의 userId === userId 비교
if (value.userId === userId) {
channels.push(value);
}
})
res.status(200).json(channels);
} else {
res.status(404).json({
message : `조회할 채널이 없어요`
})
}
})
POSTMAN) 회원 가입 2명 가입시키고, userId1에 채널 3개 만들고, userId2에 채널 2개 만들고, 전체 채널 조회
그럼 body값에 아무것도 적지 않고, 전체 채널 조회를 하면?
: 아무것도 날아오지 않는다. body값에 userId를 넣지 않았기 때문 그러나 status는 200-> 예외처리 해줘야함
그리고 존재 하지 않는 userId3을 넣어서 가지고 있는 채널들을 검색해본다면?
: 값이 나오고 status도 200 으로 정상적으로 나온다 -> 예외처리 해줘야함
결국, body값에 userId가 없어도 문제, 생성된 채널을 가지고 있지 않은 userId로 검색해도 문제라는 것을 알 수 있다
=> 이 두 부분에 대한 예외 처리 필요
// channels.js
// 예외 처리 2가지
// 1) userId가 body에 없으면
// 이 부분은 고려하지 않아도 됨
// 마이 페이지 -> 채널 관리 버튼을 눌러야하므로
// 이미 로그인 되어있기 때문
// 그럼 몇일 지나고, 로그인이 풀린 상태에서 (로그인 만료)
// 채널 관리 버튼을 누르면??
// 이 때는 body값에 userId가 없음
// 요럴 때에는 그럼 로그인 하러 가라고 지시하면 됨
// 로그인 페이지로 이동시키면 되겠지
// 그런데 지금 로그인 페이지가 없으므로, 로그인하라고 메시지를 던질 예정
// 2) userId가 가진 채널이 없으면
// forEach문을 돌았는데 맞는게 없어서 push가 되는게 하나도 없으면
// 404 오류를 보내기
router
.route('/')
.get((req, res) => {
if(db.size) {
let channels = [];
const {userId} = req.body;
if(userId == undefined) { // 1) userId가 없으면
res.status(404).json({
message : `로그인이 필요한 페이지에요`
})
} else {
db.forEach(function(value, key) {
if (value.userId === userId) {
channels.push(value);
}
})
if(channels.length == 0) { // 2) userId을 가진 채널이 없으면
res.status(404).json({
message : "조회할 채널이 없어요"
})
} else {
res.status(200).json(channels);
}
}
} else {
res.status(404).json({
message : `조회할 채널이 없어요`
})
}
});
POSTMAN) GET + localhost:7777/channels + (body) 아무것도 넣지 않았을 때
POSTMAN) GET + localhost:7777/channels + (body) {”userId” : “userId3”}
: 수많은 if else문 줄이기 (논리연산자, 콜백함수 이용)
// channels.js
router
.route('/')
.get((req, res) => {
const {userId} = req.body;
let channels = [];
if(db.size && userId) {
db.forEach(function(value, key) {
if (value.userId === userId) {
channels.push(value);
}
})
if(channels.length) {
res.status(200).json(channels);
} else {
notFoundChannel();
}
} else {
notFoundChannel();
}
})
function notFoundChannel() {
res.status(404).json({
message : `조회할 채널이 없어요`
});
}
})
매개변수를 비구조화해 조금 더 고도화해 볼 수 있을지 생각해보기,
include 함수 이용해보기,
등등 여러 가지 방법을 더 사용해서 코드를 줄일 수 있으면 좋겠다고 하셨음
이 부분은 좀 익숙해지면 찾아서 해봐야겠다..
: 앞에서 채널 생성, 전체 채널 조회 API도 수정했기 때문에 다른 API들도 역시 수정 해줘야한다.(회원 테이블에서 id칼럼 삭제함)
앞서 봤던 API는,
${name}님 환영합니다 + 메인 페이지
${name}님 환영합니다 + 로그인 페이지
${name}님 탈퇴되었습니다 or 메인 페이지
였지만, 다시 수정해서 설계해보자.
로그인
${loginUser.name}님 로그인 되었어요
회원 가입
${name}님 환영해요
채널 개별 조회
usrId, name
채널 개별 삭제
${name}님 다음에 또 봐요!
: userId가 id 대신 key가 되었으므로 가입부터 수정해줘야한다 (데이터를 userId를 사용해서 넣기 때문에)
// users.js
rotuer.post('/join', (req, res) => {
if(req.body == {}) {
res.status(400).json({
message : `입력값을 다시 확인해주세요`
})
} else {
const {userId} = req.body
db.set(userId, req.body);
res.status(201).json({
message : `${db.get(userId).name}님 환영해요`
})
}
})
router
.route('/users')
.get((req, res)=> {
let {userId} = req.body;
const user = db.get(userId);
if(user) {
res.status(200).json({
useId : user.userId,
name : user.name
})
} else {
res.status(404).json({
message : `회원 정보가 없어요`
})
}
})
router
.route('/users')
.delete((req, res)=> {
let {userId} = req.body;
const user = db.get(userId);
if(user) {
db.delete(userId);
res.status(200).json({
message : `${user.name}님 다음에 또 봐요!`
})
} else {
res.status(404).json({
message : `회원 정보가 없어요`
})
}
})
router.post("/login", function (req, res) {
const { userId, password } = req.body;
let loginUser = {};
db.forEach((user, id) => {
if (user.userId === userId) {
loginUser = user;
}
});
if (isExisted(loginUser)) {
if (loginUser.password === password) {
res.status(200).json({
message : `${loginUser.name}님 로그인 되었어요`
})
} else {
res.status(400).json({
message : `비밀번호가 틀렸어요`
})
}
} else {
res.status(404).json({
message : `회원 정보가 없어요`
})
}
});
function isExisted(obj) {
if (Object.keys(obj).length) {
return true;
} else {
return false;
}
}
개별 삭제. 조회 할 때는 url에 이제 id값을 넣지 않고 body에 userId 넣어서 확인해야함
🍎🍏 오늘의 느낀 점 : 라우터를 사용해 각 파일들을 연결하고, 또 erd를 그려보면서 다시 API를 설계 하면서 데이터베이스를 잘 계획하는게 중요하는구나를 느끼게 되었다. 그리고 예외처리들을 적용해주면서 앞으로 내가 정말 실제로 예외를 처리해 줄 때 많은 것들을 생각해주면서 코드를 짜야겠다는 생각이 들었다.. 클린코드문으로도 적어야하고 생각할 수 있는 다양한 예외들도 다 적어줘야 하니 많은 연습이 필요할 것 같다..!