์ด์ ์ ์ด์ด router์ ์ฌ์ฉํ์ฌ ์ฝ๋ ๊ฐ์ ์์ ์ ์งํํ์๋ค. ๊ธฐ์กด์ ๊ตฌํํ๋ API๋ฅผ ๋ชจ๋ํํ๊ณ , ๊ตฌ์กฐํํ๋ฉด์ ๋ ํจ์จ์ ์ธ ์ฝ๋ ๊ด๋ฆฌ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ๋ค
โญ์๋ฒ์ ๋ผ์ฐํฐ
์ด์ ์๋ ์ ๋ฆฌํ์ง๋ง ํ ๋ฒ ๋ ๊ฐ๋จํ๊ฒ ์ ๋ฆฌํ๊ณ ๋์ด๊ฐ๊ธฐ
์๋ฒ
ํด๋ผ์ด์ธํธ๋ก๋ถํฐ HTTP ์์ฒญ์ ๋ฐ์ ์ฒ๋ฆฌํ๋ ์ฃผ์ฒด
Express์์ app
๊ฐ์ฒด๊ฐ ์๋ฒ์ ์ญํ ์ ๋ด๋นํ๋ฉฐ, ๋ชจ๋ ์์ฒญ์ ์ด ์๋ฒ๋ฅผ ํตํด ์ฒ๋ฆฌ๋๋ค.
const express = require("express");
const app = express();
app.listen(7773);
๋ผ์ฐํฐ
ํด๋ผ์ด์ธํธ์ ์์ฒญ URL์ ๋ฐ๋ผ ์ ์ ํ ๊ฒฝ๋ก๋ก ์์ฒญ์ ์ ๋ฌํ๋ ์ญํ .
์ฝ๊ฒ ๋งํด, ์์ฒญ์ด ๋ค์ด์์ ๋ "์ด๋ค ํจ์๊ฐ ์ด ์์ฒญ์ ์ฒ๋ฆฌํ ์ง" ๊ฒฐ์ ํ๋ค!
const userRouter = require("./routes/user-demo");
const channelRouter = require("./routes/channel-demo");
app.use("/", userRouter);
app.use("/channels", channelRouter);
app.user("/", userRouter)
๋ ๋ฃจํธ ๊ฒฝ๋ก๋ก ์์ํ๋ ๋ชจ๋ ์์ฒญ์userRouter
๊ฐ ์ฒ๋ฆฌํ๋๋ก ์ค์ ํ๋ค.- ๋ง์ฐฌ๊ฐ์ง๋ก
/channels
๋ก ์์ํ๋ ๋ชจ๋ ์์ฒญ์channelRouter
๊ฐ ์ฒ๋ฆฌํ๋ค.
โญ๋ผ์ฐํ
์์ฒญ์ด ๋ ์์์ ๋ ํด๋น ์์ฒญ์ URL๊ณผ HTTP ๋ฉ์๋์ ๋ฐ๋ผ ์ ์ ํ ์ฝ๋๋ ์ฝ๋ฐฑ ํจ์๋ก ์ฐ๊ฒฐํ๋ ๊ณผ์
๐๋ผ์ฐํฐ ๋ชจ๋ํ
Express์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ ์ค ํ๋๋ express.Router()
ํด๋์ค๋ฅผ ํตํด ๋ผ์ฐํฐ๋ฅผ ๋ชจ๋ํ ํ ์ ์๋ค๋ ์ ์ด๋ค. ์ฝ๋์ ๊ฐ๋
์ฑ์ด ํฅ์๋๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์์ง๋ค.
ํ๋ก์ ํธ ๊ตฌ์กฐ
/
โโโ app.js // ์ ํ๋ฆฌ์ผ์ด์
์ ๋ฉ์ธ ํ์ผ
โโโ routes/
โโโ user-demo.js // ์ฌ์ฉ์ ๊ด๋ จ ๋ผ์ฐํฐ
โโโ channel-demo.js // ์ฑ๋ ๊ด๋ จ ๋ผ์ฐํฐ
์ฌ๊ธฐ์ routes
ํด๋๋ ๋ชจ๋ ๋ผ์ฐํฐ ํ์ผ์ ๊ด๋ฆฌํ๋ ๋๋ ํ ๋ฆฌ์ด๋ค. ๊ฐ ๋ผ์ฐํฐ ํ์ผ์ ๊ด๋ จ ๋ฆฌ์์ค(์ฌ์ฉ์, ์ฑ๋)์ ๋ํ ์๋ํฌ์ธํธ๋ฅผ ์ ์ํ๋ค.
app.js
์๋ฒ ์ค์ ๋ฐ ๋ผ์ฐํฐ ๋ฑ๋ก
const express = require("express");
const app = express();
app.listen(7773);
const userRouter = require("./routes/user-demo");
const channelRouter = require("./routes/channel-demo");
app.use("/", userRouter);
app.use("/channels", channelRouter);
app.js
๋ Express ์ ํ๋ฆฌ์ผ์ด์
์ ์ง์
์ ์ผ๋ก, ์๋ฒ๋ฅผ ์ค์ ํ๊ณ ํ์ํ ๋ผ์ฐํฐ๋ฅผ ๋ฑ๋กํ๋ค. ํ์ฌ, ๋ ๊ฐ ๋ผ์ฐํฐ๋ฅผ ์ฌ์ฉํ๋ค.
userRouter
: ๋ฃจํธ ๊ฒฝ๋ก์ ๋ฑ๋ก๋์ด ์ฌ์ฉ์ ๊ด๋ จ API ์ฒ๋ฆฌchannelRouter
: /channels ๊ฒฝ๋ก์ ๋ฑ๋ก๋์ด ์ฑ๋ ๊ด๋ จ API๋ฅผ ์ฒ๋ฆฌ
์ฝ๋ ๊ฐ์ ์ฌํญ
1. app->router๋ก ๋ณ๊ฒฝ
๊ธฐ์กด ์ฝ๋์์๋ ๋ชจ๋ ๋ผ์ฐํธ๋ฅผ app ๊ฐ์ฒด์ ์ง์ ๋ฑ๋กํ์ง๋ง, ๋ฆฌํฉํ ๋ง๋ ์ฝ๋์์๋ Express Router๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ํํ์๋ค.
//๋ณ๊ฒฝ ์
app.post("/login", function (req, res) { /* ... */ });
app.post("/signup", function (req, res) { /* ... */ });
//๋ณ๊ฒฝ ํ
const router = express.Router();
router.post("/login", function (req, res) { /* ... */ });
router.post("/signup", function (req, res) { /* ... */ });
module.exports = router;
2. userId๋ฅผ Key๋ก ์ฌ์ฉ
๊ธฐ์กด์๋ ์์ฐจ์ ์ธ id๋ฅผ key๋ก ์ฌ์ฉํ์ง๋ง, userId๋ฅผ key๋ก ์ฌ์ฉํ๋๋ก ๋ณ๊ฒฝํ์๋ค.
//๋ณ๊ฒฝ ์
let db = new Map();
var id = 1;
app.post("/signup", function (req, res) {
if (req.body !== undefined && req.body.userId) {
db.set(id++, req.body);
// ...
}
});
//๋ณ๊ฒฝ ํ
let db = new Map();
// var id = 1; // ๋ ์ด์ ํ์ํ์ง ์์ - userId๋ฅผ ํค๋ก ์ฌ์ฉ
router.post("/signup", function (req, res) {
if (req.body !== undefined && req.body.userId) {
const userId = req.body.userId;
// ์ด๋ฏธ ์กด์ฌํ๋ ์์ด๋์ธ์ง ํ์ธ
if (db.has(userId)) {
return res.status(409).json({ message: "์ด๋ฏธ ์กด์ฌํ๋ ์์ด๋์
๋๋ค." });
}
db.set(userId, req.body);
// ...
}
});
userId
๋ก ์ฌ์ฉ์๋ฅผ ๋ฐ๋ก ์ฐพ์ ์ ์์ด ์กฐํ ์ฑ๋ฅ ํฅ์- ์ค๋ณต ์์ด๋ ํ์ธ์ด
db.has(userId)
๋ก ๊ฐ๋จํด์ง - ๋ณ๋์ id ๋ณ์ ๊ด๋ฆฌ ๋ถํ์
3. ์์ธ์ฒ๋ฆฌ ๊ฐ์
์ฝ๋ ์ ๋ฐ์ ๊ฑธ์ณ ์์ธ ์ฒ๋ฆฌ๋ฅผ ๋ ๊ฐํํ์๋ค.
๋ก๊ทธ์ธ ์ ์์ธ์ฒ๋ฆฌ
router.post("/login", function (req, res) {
// userId๋ password๊ฐ ์๋ ๊ฒฝ์ฐ ์์ธ ์ฒ๋ฆฌ
if (!req.body || !req.body.userId || !req.body.password) {
return res
.status(400)
.json({ message: "์์ด๋์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ชจ๋ ์
๋ ฅํด์ฃผ์ธ์." });
}
// ...userId๋ฅผ ์ง์ ํค๋ก ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์กฐํ
const loginUser = db.get(userId);
if (!loginUser) {
return res.status(401).json({ message: "์กด์ฌํ์ง ์๋ ์์ด๋์
๋๋ค" });
}
// ...
});
์ฑ๋ API์์ ์์ธ์ฒ๋ฆฌ
// ์ฑ๋์ ์ฐพ์ง ๋ชปํ์ ๋ ๊ณตํต ์๋ต ํจ์
function notFoundChannel(res) {
return res.status(404).json({ message: "์ฑ๋์ ์ฐพ์ ์ ์์ต๋๋ค." });
}
// ์ฌ์ฉ ์
router.get("/user/:userId", (req, res) => {
// ...
if (db.size === 0) {
return notFoundChannel(res);
}
// ...
if (userChannels.length === 0) {
return notFoundChannel(res);
}
// ...
});
notFoundChannel
๊ฐ์ ๊ณตํต ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ณต ์ฝ๋๋ฅผ ๊ฐ์return
์ ํ์ฉํearly exit
ํจํด์ผ๋ก ์ฝ๋ ๊ฐ๋ ์ฑ ํฅ์
์ฑ๋ API ์ถ๊ฐ ๊ธฐ๋ฅ
// ํน์ ์ฌ์ฉ์๊ฐ ์์ฑํ ์ฑ๋ ๋ชฉ๋ก ์กฐํ
router.get("/user/:userId", (req, res) => {
const { userId } = req.params;
if (db.size === 0) {
return notFoundChannel(res);
}
const userChannels = [];
db.forEach((channel, key) => {
if (channel.userId === userId) {
userChannels.push({ ...channel, id: key });
}
});
if (userChannels.length === 0) {
return notFoundChannel(res);
}
res.status(200).json({
message: "์ฌ์ฉ์ ์ฑ๋ ์กฐํ ์ฑ๊ณต",
channels: userChannels,
});
});
//์ฑ๋ ์์ฑ ์ userId ํ๋
let channel = {
channelName: req.body.channelName,
userId: req.body.userId, // ์ฌ์ฉ์ ID ์ถ๊ฐ
createdAt: new Date().toISOString(),
};
์ฑ๋ ์์ฑ์ userId
ํ๋๋ฅผ ์ถ๊ฐํ์ฌ ์ด๋ค ์ฌ์ฉ์๊ฐ ์ฑ๋์ ์์ฑํ๋์ง ์ถ์ ํ ์ ์๊ฒ ๋์๋ค. ์ด์ , ํน์ ์ฌ์ฉ์๊ฐ ์์ฑํ ๋ชจ๋ ์ฑ๋์ ์กฐํํ๋ API๊ฐ ์ถ๊ฐ๋์๋ค.
โ์ฝ๊ฐ์ ๋ณด์์ด์
userId
๊ฐ์ ๊ฐ์ ์๋ ํค๋์ ์ค์ด๋ณด๋ด๋ ๊ฐ์ธ๋ฐ, ์ฐ์ ๋ฐ๋์ ํฌํจํ๋๋ก ๊ตฌ์ฑํ๋ค. ์ค์ ํ๋ก๋์
ํ๊ฒฝ์์๋ ์ฌ์ฉ์ ์ธ์ฆ์ ์ํด JWT ๊ฐ์ ํ ํฐ์ ์ฌ์ฉํ๊ณ , ์ด ํ ํฐ์ ๋ณดํต HTTP ํค๋์ Authorization ํ๋์ ํฌํจ๋๋ค.
// ํ ํฐ ์ธ์ฆ ๋ฐฉ์ ๋ง๋ณด๊ธฐ
router.get("/users/me", authenticateToken, (req, res) => {
// req.user๋ authenticateToken ๋ฏธ๋ค์จ์ด๋ฅผ ํตํด ์ค์ ๋ ๊ฐ
const user = db.get(req.user.userId);
res.json(user);
});
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401);
// ํ ํฐ ๊ฒ์ฆ ๋ก์ง...
}
์ด๊ฒ๋ ์ฐจ์ฐจ ๋ฐฐ์ธ ๋ด์ฉ...!
์ฝ๋ ๊ฐ์ ์์ ์ ํตํด Express ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์กฐํ์ ๋ชจ๋ํ, ๊ทธ๋ฆฌ๊ณ ๋ ๋์ ์์ธ์ฒ๋ฆฌ ๋ฐฉ๋ฒ์ ์ ์ ์์๋ค. ํ๋ํ๋ ๋ฐฐ์ธ์๋ก ์ด๋ป๊ฒ ํ๋ฉด ๋ ๊ตฌ์กฐ์ ์ผ๋ก API๋ฅผ ๋ง๋ค ์ ์์์ง ์๊ฐ์ด ์ ์ ๋ง์์ง๋ ๊ฒ ๊ฐ๋ค.
์ด์ ๋ ์ง์ง ๊ธฐ๋ฅ๋ ๋ค์ํ๋ฐ, ์ฌ์ฌ ๋ฐ์ดํฐ ์ฐ๋์ ํด๋ณด์ง ์์ผ๋ ค๋. ์ค๋ ๊ฐ์ ์ค ERD ํํธ๋ ์๋๋ฐ ์ฌ์ฌ DB ์ฐ๋๋ ํ์ง ์์๊น ๊ธฐ๋์ค์ ๋๋ค.