Router
별도로 작성되어 있는 회원 기능과 채널 기능이 한 번에 모두 작동되게 만들어보자.
참고로 user-demo.js와 channel-demo.js 파일명을 각각 users.js, channels.js로 변경해 주었다.
두 모듈을 불러올 파일 app.js를 생성한다. 이 파일에서 서버를 가동할 것이다.
app.js에서 모듈을 불러오려면 users.js와 channels.js에서 모듈을 내보내야 한다. 따라서 두 파일 모두 아래의 절차를 따른다.
- users.js와 channels.js에서 서버를 가동시키는 listen 부분을 없애준다. (app.js에서 서버를 가동하기 때문)
- router이라는 변수에 express의 Router 함수를 담는다.
- epress의 Router 함수는 라우터를 분리할 수 있게 해 준다.
- 만약 Router 함수를 사용하지 않는다고 해보자. 그러면 app.js에서 회원 기능과 채널 기능에 관련된 모든 라우팅을 하게 될 것이다. 코드가 길어지고 각 기능을 처리하는 코드가 한 파일에 섞여있으니 가독성이 떨어질 것이다. 규모가 커지게 되면 유지보수 또한 힘들어진다.
- 모든 API의 app 변수를 router로 수정한다.
- module.exports = router로 다른 파일에서 이 모듈에 접근할 수 있게 해 준다.
const express = require('express');
const router = express.Router();
// body 파싱 미들웨어
router.use(express.json());
const db = new Map();
let id = 1;
router.post('/login', (req, res) => {
// ...
})
// ...
module.exports = router;
app.js에서는 다음과 같은 절차를 수행한다.
- express 모듈을 세팅하고, listen으로 서버를 가동하는 코드를 작성한다.
- users.js와 channels.js의 모듈을 불러온다.
- 2에서 불러온 모듈을 미들웨어로 추가한다. 첫 번째 파라미터는 접두사 문자열이다. 이 문자열은 해당하는 모듈에 작성된 라우팅 경로의 앞에 붙게 되므로 라우팅 경로에 공통된 url이 있다면 이 접두사에 적고, 해당 모듈의 경로에서 지운다. 두 번째 파라미터는 2에서 모듈을 불러와서 저장한 변수이다.
const express = require('express');
const app = express();
app.listen(3000);
const userRouter = require('./routes/users');
const channelRouter = require('./routes/channels');
app.use('/', userRouter);
app.use('/channels', channelRouter);
회원 - 채널 ERD
현재는 DB에 id라는 정수를 키로 객체를 저장하고 있었지만 회원의 id가 유니크하기 때문에 DB에서 키로 사용되고 있는 id는 필요 없다. 따라서 DB의 키는 회원의 id(PK)를 사용할 것이고, 이 id는 채널을 생성할 때 누구 소유의 채널인가를 나타낼 때(FK)도 사용된다. 채널명은 유니크하지 않을 수 있기 때문에 지금과 동일하게 정수인 id(PK)를 사용한다.
참고로, ERD 테이블에서 컬럼명은 snake_case를 사용한다.
채널 API 수정
설계
채널을 생성할 때 userId를 받게 되는데. 원래는 이 값은 헤더로 받아야 하지만 지금은 body에 넣어서 받을 것이다.
기능 | 메서드 | 경로 | 요청 | 응답 |
채널 생성 | POST | /channels | body (channelTitle, userId) | 환영 메시지 → 채널 관리 페이지 |
회원 채널 전체 조회 | GET | /channels | body (userId) | 채널 전체 데이터 list, json array |
코드
로그인을 해야 채널을 생성, 조회할 수 있기 때문에 로그인된 userId를 request의 body 받는다.
그리고 두 가지 경우에 대한 예외 처리를 수행한다.
- userId가 누락된 경우 로그인이 필요한 페이지라는 메시지를 전송한다.
- userId가 가진 채널이 없는 경우 채널 정보가 없다는 메시지를 전송한다.
router.route('/')
.get((req, res) => {
const { userId } = req.body;
let channels = [];
if (db.size && userId) {
db.forEach((channel, key) => {
if (channel.userId === userId)
channels.push(channel);
})
channels.length ? res.status(200).json(channels) : notFoundChannel(res);
} else if (!userId) {
res.status(404).json({
message: '로그인이 필요한 페이지 입니다.'
})
} else {
notFoundChannel(res);
}
}) // 회원의 채널 전체 조회
.post((req, res) => {
const channel = req.body;
if (channel.channelTitle && channel.userId) {
db.set(id++, channel);
res.status(201).json({
message: `${db.get(id - 1).channelTitle}채널을 응원합니다!`
});
} else if (!channel.userId) {
res.status(404).json({
message: '로그인이 필요한 페이지 입니다.'
});
} else {
res.status(400).json({
message: '요청 값을 제대로 보내주세요.'
});
}
}) // 채널 개별 생성
function notFoundChannel(res) {
res.status(404).json({
message: '채널 정보를 찾을 수 없습니다.'
})
}
회원 API 수정
설계
DB의 key으로 사용하던 정수 id 대신 회원의 id를 key로 사용한다. 회원의 id 또한 개인정보이기 때문에 URL에 적을 수 없으므로 경로를 다음과 같이 수정한다.
기능 | 메서드 | 경로 | 요청 | 응답 |
회원 개별 조회 | GET | /users | body (userId) | userId, name |
회원 개별 탈퇴 | DELETE | /users | body (userId) | 탈퇴 메시지 또는 메인 페이지 |
코드
회원가입을 할 때 DB에 userId를 key로 설정하는 부분이 수정되었다.
회원 개별 조회, 회원 개별 탈퇴의 경로가 기존 '/users/:id'에서 '/users'로 수정되었다.
회원 정보를 찾을 수 없다는 응답을 보내는 코드가 중복되기 때문에 함수로 만들어 수정하였다.
// 회원가입
router.post('/join', (req, res) => {
if (Object.keys(req.body).length) {
const { userId } = req.body;
db.set(userId, req.body)
res.status(201).json({
message: `${db.get(userId).name}님, 환영합니다!`
})
} else {
res.status(400).json({
message: "입력 값을 다시 확인해주세요."
})
}
})
router.route('/users')
.get((req, res) => {
const { userId } = req.body
const user = db.get(userId);
if (user) {
res.status(200).json({
userId: user.userId,
name: user.name
})
} else {
notFoundUser(res);
}
}) // 회원 개별 조회
.delete((req, res) => {
const { userId } = req.body;
const user = db.get(userId);
if (user) {
db.delete(userId);
res.status(200).json({
message: `${user.name}님, 다음에 또 뵙겠습니다.`
})
} else {
notFoundUser(res);
}
}) // 회원 개별 삭제
function notFoundUser(res) {
res.status(404).json({
message: '회원 정보를 찾을 수 없습니다.'
})
}
'데브코스' 카테고리의 다른 글
[풀 사이클 개발 데브코스 회고] 3월 회고 (0) | 2024.03.28 |
---|---|
[5주차 - DAY3] Express.js 응용 (1) | 2024.03.27 |
[5주차 - DAY1] REST API 개발 실습(1) (0) | 2024.03.25 |
[4주차 - DAY5] Node.js 및 Express.js를 사용한 서버 개발 실습(3) (1) | 2024.03.22 |
[4주차 복습 발표] API 설계 실습 (0) | 2024.03.21 |