Node.js ์ค์ต ์ฝ๋ ๋ณต๊ธฐ
์ด ๊ธ์ ๋ชฉ์ฐจ75๊ฐ
- ๐ ์ค์ต ์๊ฐ
- ๐งฉ ์ฌ์ฉ ๊ธฐ์ ์คํ
- ๐ ํด๋ ๊ตฌ์กฐ (์ค์ ํ์ผ๋ง ์์ฝ)
- ๐ ๊ตฌํ๋ ์ฃผ์ ๊ธฐ๋ฅ
- ๐ง ๋ฐฐ์ด ๊ฐ๋ ๋ค
- ๐ ์ ์ฒด ์ฝ๋
- โ ์ฝ๋ ์ค๋ช
- 1. require() โ ๋ชจ๋ ๋ถ๋ฌ์ค๊ธฐ
- ๐ ์ง๋ฌธ : require("dotenv").config();๋?
- ๐ ์ง๋ฌธ : .env ํ์ผ์ด ๋ณดํธ๋ฐ๋ ์๋ฆฌ๋?
- 2. dbConnect(); โ MongoDB ์ฐ๊ฒฐ
- 3. ๋ฏธ๋ค์จ์ด ์ค์
- ๋ฏธ๋ค์จ์ด(Middleware)๋?
- 4. ๋ทฐ ํ ํ๋ฆฟ ์ค์
- โ EJS๋?
- โ ์ฌ์ฉ ์ด์
- โ ์ฃผ์ ํน์ง
- 5. ์ ์ ํ์ผ ๋ฑ๋ก
- 6. ๋ผ์ฐํฐ ๋ฑ๋ก
- โ ๋ผ์ฐํฐ(Router)๋?
- โ ๋ผ์ฐํฐ๋ฅผ ์ฐ๋ ์ด์ ?
- 7. ์๋ฒ ์คํ
- โ ๋ฐฐ์ด ๊ฐ๋ ๋ค ๋ฆฌ๋ง์ธ๋
- ๐ ์ ์ฒด ์ฝ๋
- โ ๋ผ์ฐํฐ๋?
- ๐ app.js์ ์ฐ๊ฒฐ ๊ตฌ์กฐ ๋ณต์ต
- โ ์ฃผ์ ๋ผ์ฐํ
- 1. ์ ์ฒด ์ฐ๋ฝ์ฒ ๋ชฉ๋ก ์กฐํ
- 2. ์ฐ๋ฝ์ฒ ์ถ๊ฐ ํผ ๋ณด์ฌ์ฃผ๊ธฐ
- 3. ์ฐ๋ฝ์ฒ ์์ฑ (POST)
- โ req.body์ ์ ๋ณด๊ฐ ์ด๋ป๊ฒ ์ ๋ณด๊ฐ ๋ด๊ธธ๊น?
- 4. ์ฐ๋ฝ์ฒ ์์ธ ์กฐํ (์์ ํผ)
- โ /:id์ ์๋ฏธ๋?
- ์ฆ, :id๋ ๋ณ์์ฒ๋ผ ๋์ํ๋ค.
- ๐งฉ ์์
- 5. ์ฐ๋ฝ์ฒ ์์
- โ ์ HTML ํผ์์๋ GET, POST๋ง ์ง์ํ ๊น?
- ๐ ์ด์ :
- โ ๊ทธ๋ผ PUT/DELETE์ ์ธ์ ์ฌ์ฉ ๊ฐ๋ฅํ ๊น?
- โ ํด๊ฒฐ ๋ฐฉ๋ฒ: method-override ๋ชจ๋
- ๐ ์ฌ์ฉ ๋ฐฉ๋ฒ
- โ ๋์ ๋ฐฉ์:
- โ ์์ฝ
- 6. ์ฐ๋ฝ์ฒ ์ญ์
- ๐ ์ต์ข ์ ๋ฆฌ: ์ฒ๋ฆฌ ํ๋ฆ
- โ ๋ฐฐ์ด ๊ฐ๋ ๋ค ๋ฆฌ๋ง์ธ๋
- ๐ ์ ์ฒด ์ฝ๋
- โ ์ปจํธ๋กค๋ฌ๋?
- โ ํจ์๋ณ ์ค๋ช
- 1. ์ ์ฒด ์ฐ๋ฝ์ฒ ์กฐํ - getAllContacts
- 2. ์ฐ๋ฝ์ฒ ์ถ๊ฐ ํผ - addContactForm
- 3. ์ฐ๋ฝ์ฒ ์ถ๊ฐ ์ฒ๋ฆฌ - createContact
- 4. ์์ ํผ ๋ถ๋ฌ์ค๊ธฐ - getContact
- 5. ์ฐ๋ฝ์ฒ ์์ ์ฒ๋ฆฌ - updateContact
- 6. ์ฐ๋ฝ์ฒ ์ญ์ - deleteContact
- โ ๊ด๋ จ ๊ฐ๋ ์ ๋ฆฌ
- ๐ loginRoute.js โ ๋ก๊ทธ์ธ ๋ฐ ํ์๊ฐ์ ๋ผ์ฐํฐ
- ๐ ์ ์ฒด ์ฝ๋
- โ ๊ฒฝ๋ก๋ณ ๋ผ์ฐํ ์ค๋ช
- 1. router.get("/") โ ๋ก๊ทธ์ธ ํผ
- 2. router.post("/") โ ๋ก๊ทธ์ธ ์์ฒญ ์ฒ๋ฆฌ
- 3. router.get("/register") โ ํ์๊ฐ์ ํผ
- 4. router.post("/register") โ ํ์๊ฐ์ ์ฒ๋ฆฌ
- โ ์ router.get("/")์ด ๋ฃจํธ ๊ฒฝ๋ก๋ฅผ ์๋ฏธํ ๊น?
- ๐ loginController.js โ ๋ก๊ทธ์ธ ๋ฐ ํ์๊ฐ์ ์ฒ๋ฆฌ ๋ก์ง
- ๐ ์ ์ฒด ์ฝ๋
- โ ํจ์๋ณ ์ค๋ช
- 1. ๋ก๊ทธ์ธ ํผ ๋ณด์ฌ์ฃผ๊ธฐ - getLogin
- 2. ๋ก๊ทธ์ธ ์ฒ๋ฆฌ - loginUser
- 3. ํ์๊ฐ์ ํผ ๋ ๋๋ง - getRegister
- 4. ํ์๊ฐ์ ์ฒ๋ฆฌ - registerUser
- โ ์ง๋ฌธ
- catch(error)๋ ์ด๋ค ์ํฉ์์ ์คํ๋ ๊น?
- Q3. module.exports = { ... } ๋ ๋ญ๊น?
- โ ๊ฐ๋ ์ ๋ฆฌ
๐ ์ฐ๋ฝ์ฒ ๊ด๋ฆฌ ์น์ฑ (Node.js & Express / MongoDB, EJS, JWT ์ธ์ฆ)
๐ ์ค์ต ์๊ฐ
Node.js + Express + MongoDB + EJS ํ ํ๋ฆฟ ์์ง์ ๊ธฐ๋ฐ์ผ๋ก ํ ์ฐ๋ฝ์ฒ ๊ด๋ฆฌ ์น ์ ํ๋ฆฌ์ผ์ด์
ํ์๊ฐ์
โ ๋ก๊ทธ์ธ โ ์ฐ๋ฝ์ฒ ๋ฑ๋ก/์กฐํ/์์ /์ญ์ ๊ธฐ๋ฅ(CRUD)์ ๊ตฌํํ๋ฉด์ ๋ฐฑ์๋์ ์๋ฒ ๋์ ์๋ฆฌ๋ฅผ ์ค์ต

๐งฉ ์ฌ์ฉ ๊ธฐ์ ์คํ
| ๊ธฐ์ | ์ค๋ช |
|---|---|
| Node.js | ์๋ฐ์คํฌ๋ฆฝํธ ๋ฐํ์ |
| Express | ์๋ฒ ๊ตฌ์ถ์ ์ํ ํ๋ ์์ํฌ |
| MongoDB | NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค |
| Mongoose | MongoDB ODM (๊ฐ์ฒด ๋ชจ๋ธ๋ง) |
| EJS | ํ ํ๋ฆฟ ์์ง (HTML์ JS ์ฝ์ ) |
| JWT | ๋ก๊ทธ์ธ ์ธ์ฆ์ฉ JSON Web Token |
| cookie-parser | ์ฟ ํค ์ ์ฅ ๋ฐ ์ธ์ฆ์ ์ํ ๋ฏธ๋ค์จ์ด |
| dotenv | ํ๊ฒฝ๋ณ์ ๊ด๋ฆฌ |
๐ ํด๋ ๊ตฌ์กฐ (์ค์ ํ์ผ๋ง ์์ฝ)
myContacts/
โโโ app.js # ์๋ฒ ๋ฉ์ธ ํ์ผ
โโโ .env # ํ๊ฒฝ๋ณ์
โโโ config/
โ โโโ dbConnect.js # MongoDB ์ฐ๊ฒฐ ์ค์
โโโ controllers/
โ โโโ contactController.js
โ โโโ loginController.js
โโโ models/
โ โโโ contactModel.js
โ โโโ userModel.js
โโโ routes/
โ โโโ contactsRoutes.js
โ โโโ loginRoute.js
โโโ views/
โ โโโ index.ejs # ์ฐ๋ฝ์ฒ ๋ชฉ๋ก
โ โโโ add.ejs # ์ฐ๋ฝ์ฒ ์ถ๊ฐ
โ โโโ update.ejs # ์ฐ๋ฝ์ฒ ์์
โ โโโ home.ejs # ๋ก๊ทธ์ธ ํ์ด์ง
โ โโโ register.ejs # ํ์๊ฐ์
โ โโโ includes/
โ โโโ _header.ejs
โ โโโ _footer.ejs
โโโ public/
โ โโโ style.css
โโโ package.json
๐ ๊ตฌํ๋ ์ฃผ์ ๊ธฐ๋ฅ
- ๐ ํ์๊ฐ์
& ๋ก๊ทธ์ธ ๊ธฐ๋ฅ
- bcrypt๋ก ๋น๋ฐ๋ฒํธ ์ํธํ
- JWT๋ก ๋ก๊ทธ์ธ ํ ํฐ ๋ฐ๊ธ
- ์ฟ ํค์ ํ ํฐ ์ ์ฅ
- ๐ ์ฐ๋ฝ์ฒ CRUD ๊ธฐ๋ฅ
- ์ฐ๋ฝ์ฒ ๋ฑ๋ก, ๋ชฉ๋ก ์กฐํ, ์์ , ์ญ์
- MongoDB์ ์ ์ฅ
- EJS ํ ํ๋ฆฟ์ผ๋ก ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ
- ๐ก ๋ฏธ๋ค์จ์ด, ๋ผ์ฐํ
, ์ปจํธ๋กค๋ฌ ๋ถ๋ฆฌ
- MVC ํจํด ํ์ต
๐ง ๋ฐฐ์ด ๊ฐ๋ ๋ค
- ๋ผ์ฐํฐ โ ์ปจํธ๋กค๋ฌ โ ๋ชจ๋ธ โ ๋ทฐ ํ๋ฆ
- HTTP ์์ฒญ ๋ฐฉ์:
GET,POST,PUT,DELETE - ๋น๋๊ธฐ ์ฒ๋ฆฌ (
async/await) - MongoDB ๊ธฐ๋ณธ ๊ตฌ์กฐ ๋ฐ CRUD
- ์ฟ ํค / ์ธ์ / JWT ์ธ์ฆ ์ฐจ์ด
- EJS์์ ์กฐ๊ฑด๋ฌธ, ๋ฐ๋ณต๋ฌธ, include ์ฌ์ฉ๋ฒ
- .env ํ๊ฒฝ๋ณ์ ์ค์ ๋ฐ ๊ด๋ฆฌ
๐ฆ app.js โ Express ์๋ฒ์ ์์์
app.js๋ ์๋ฒ ์คํ ํ๋ฆ, ๋ผ์ฐํ ๋ฑ๋ก, ๋ฏธ๋ค์จ์ด ์ค์ , ํ๊ฒฝ๋ณ์ ์ฌ์ฉ๋ฒ ๋ฑ์ ์ ๋ฆฌํ๋ค.
๐ ์ ์ฒด ์ฝ๋
// ๋ชจ๋ ๋ถ๋ฌ์ค๊ธฐ
const express = require("express");
const path = require("path");
const dbConnect = require("./config/dbConnect");
const cookieParser = require("cookie-parser");
require("dotenv").config(); // .env ํ์ผ์ ์ฝ์ด ํ๊ฒฝ๋ณ์ ์ค์
// Express ์ฑ ์ด๊ธฐํ
const app = express();
// DB ์ฐ๊ฒฐ ์คํ
dbConnect();
// ๋ฏธ๋ค์จ์ด ๋ฑ๋ก
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
// EJS ํ
ํ๋ฆฟ ์์ง ์ค์
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));
// ์ ์ ํ์ผ(css ๋ฑ) ๊ฒฝ๋ก ์ค์
app.use(express.static(path.join(__dirname, "public")));
// ๋ผ์ฐํฐ ๋ฑ๋ก
const contactsRoutes = require("./routes/contactsRoutes");
const loginRoutes = require("./routes/loginRoute");
app.use("/contacts", contactsRoutes);
app.use("/", loginRoutes);
// ์๋ฒ ์์
app.listen(3000, () => {
console.log("์๋ฒ๊ฐ 3000๋ฒ ํฌํธ์์ ์คํ ์ค์
๋๋ค.");
});
โ ์ฝ๋ ์ค๋ช
1. require() โ ๋ชจ๋ ๋ถ๋ฌ์ค๊ธฐ
const express = require("express");
const path = require("path");
express: Node.js์์ ๊ฐ์ฅ ๋๋ฆฌ ์ฐ์ด๋ ์น ์๋ฒ ํ๋ ์์ํฌpath: ํ์ผ/ํด๋ ๊ฒฝ๋ก๋ฅผ ์ค์ ํ ๋ ์ฌ์ฉํ๋ค. OS ์๊ด์์ด ์์ ํ๊ฒ ๊ฒฝ๋ก๋ฅผ ์ฐ๊ฒฐํ ์ ์๊ฒ ๋์์ค๋ค.
๐ ์ง๋ฌธ : require("dotenv").config();๋?
dotenv๋.envํ์ผ์ ์ฝ์ด์process.env.๋ณ์๋ช์ผ๋ก ์ ๊ทผํ ์ ์๊ฒ ํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.config()๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด.envํ์ผ์ด ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋๋๋ค.- ์๋ฅผ ๋ค์ด
.env์ ์์ฑ๋JWT_SECRET=123456์ด๋ผ๋ ๊ฐ์process.env.JWT_SECRET์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํด์ง๋ค.
๐ ์ง๋ฌธ : .env ํ์ผ์ด ๋ณดํธ๋ฐ๋ ์๋ฆฌ๋?
.env ํ์ผ์ Node.js ๋ด๋ถ์์๋ง ์ฌ์ฉ๋๋ ์ค์ ํ์ผ์ด๊ณ , ํด๋ผ์ด์ธํธ(๋ธ๋ผ์ฐ์ )๋ก ์ ๋ ์ ์ก๋์ง ์์ผ๋ฉฐ, .gitignore๋ก Git์ ์ ๋ก๋๋์ง ์๋๋ก ์ค์ ํ๋ ๊ฒ์ด ์์น์ด๋ค.
โ ์์ธํ ์ค๋ช
- .env ํ์ผ์ ์๋ฒ ์ธก ์ฝ๋์์๋ง ์ฌ์ฉ๋จ .env ํ์ผ์ dotenv ๋ชจ๋์ ํตํด ์๋ฒ ์คํ ์ process.env ๊ฐ์ฒด์ ๋ณ์๋ก ๋ฑ๋ก๋๋ค.
์๋ฒ์์๋ง ์ฝํ๊ณ , **๋ธ๋ผ์ฐ์ (ํด๋ผ์ด์ธํธ)**์๋ ์ ๋ ๋ ธ์ถ๋์ง ์๋๋ค.
require("dotenv").config();
const key = process.env.API_KEY; // ์๋ฒ์์๋ง ์ ๊ทผ ๊ฐ๋ฅ
โ ํด๋ผ์ด์ธํธ๊ฐ ์ด ๊ฐ์ ์ง์ ๋ณผ ์๋ ์๋ค. (HTML, JS ํ์ผ์๋ ํฌํจ๋์ง ์์)
2. dbConnect(); โ MongoDB ์ฐ๊ฒฐ
const dbConnect = require("./config/dbConnect");
dbConnect();
- DB ์ฐ๊ฒฐ ์ค์ ํจ์
- ๋ด๋ถ์์
mongoose.connect()๋ฑ์ ํธ์ถํด MongoDB ์๋ฒ์ ์ฐ๊ฒฐํ๋ค.
3. ๋ฏธ๋ค์จ์ด ์ค์
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
๋ฏธ๋ค์จ์ด(Middleware)๋?
- ํด๋ผ์ด์ธํธ ์์ฒญ(req)๊ณผ ์๋ฒ ์๋ต(res) ์ฌ์ด์์ ๋์ํ๋ ์ค๊ฐ ์ฒ๋ฆฌ ๋ก์ง์ด๋ค.
- ์๋ฅผ ๋ค์ด, ์์ฒญ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ๊ฑฐ๋, ์ธ์ฆ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ฑฐ๋, ๊ณตํต ๋ก๊ทธ๋ฅผ ์ฐ๋ ๋ฑ์ ์ญํ ์ ํ๋ค.
์ฝ๊ฒ req๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๊ณ res๋ฅผ ๋ฆฌํดํ๋ ํจ์์ ๋์์ ๋ฏธ๋ค์จ์ด๋ผ๊ณ ์ดํดํ ์ ์๋ค.
express.json():- ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ JSON ๋ฐ์ดํฐ๋ฅผ
req.body์ ์๋์ผ๋ก ๋ฃ์ด์ค๋ค. - API ์์ฒญ์์
Content-Type: application/json์ธ ๊ฒฝ์ฐ ์ฌ์ฉ๋๋ค.
- ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ JSON ๋ฐ์ดํฐ๋ฅผ
express.urlencoded({ extended: true }):- HTML form ๋ฐฉ์์ผ๋ก ์ ๋ฌ๋ ๋ฐ์ดํฐ๋ฅผ
req.body์ ๋ฃ์ด์ค๋ค. - EJS์์
<form method="POST">๋ฅผ ์ฌ์ฉํ ๋ ํ์์ด๋ค.
- HTML form ๋ฐฉ์์ผ๋ก ์ ๋ฌ๋ ๋ฐ์ดํฐ๋ฅผ
cookieParser():- ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ์ฟ ํค๋ฅผ
req.cookies๋ก ํ์ฑํด์ฃผ๋ ๋ฏธ๋ค์จ์ด์ด๋ค. - JWT ํ ํฐ ์ธ์ฆ์์ ์ฟ ํค์ ์ ์ฅ๋ ํ ํฐ์ ๊บผ๋ผ ๋ ์ฌ์ฉํ๋ค.
- ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ์ฟ ํค๋ฅผ
4. ๋ทฐ ํ ํ๋ฆฟ ์ค์
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));
- ๋ทฐ ์์ง์ผ๋ก EJS๋ฅผ ์ฌ์ฉํ๋ค๊ณ ์ง์ ํ๋ค.
โ EJS๋?
EJS (Embedded JavaScript) ๋
HTML ์์ JavaScript ์ฝ๋๋ฅผ ๋ฃ์ ์ ์๋ ํ ํ๋ฆฟ ์์ง
โ ์ฌ์ฉ ์ด์
๋ณดํต ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ HTML์ ์ ํ๊ธฐ ์ํด ์ฌ์ฉ
HTML๋ก๋ง ํ์ด์ง๋ฅผ ๋ง๋ค๋ฉด, ๊ณ ์ ๋ ์ ์ ์ธ ์นํ์ด์ง๋ง ๋ง๋ค ์ ์๋ค.
ํ์ง๋ง EJS๋ฅผ ์ฐ๋ฉด, ๋ฐฑ์๋์์ ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ํ์ด์ง์ ๋์ ์ผ๋ก ํ์ํ ์ ์๋ค.
โ ์ฃผ์ ํน์ง
| ํน์ง | ์ค๋ช |
|---|---|
| HTML ์์์ JavaScript ์ฌ์ฉ ๊ฐ๋ฅ | <%= %>, <% %> ๋ฌธ๋ฒ ์ฌ์ฉ |
| ๋ฐฑ์๋ ๋ฐ์ดํฐ์ ์ฐ๋ | ์๋ฒ์์ ๋๊ฒจ์ค ๊ฐ์ ํ์ด์ง์ ์ถ๋ ฅ ๊ฐ๋ฅ |
| ๋น ๋ฅด๊ณ ๊ฐํธ | React๋ณด๋ค ๊ฐ๋ณ๊ณ ํ์ต ๋์ด๋ ๋ฎ์ |
| Express์ ์ ์ด์ธ๋ฆผ | Node.js + Express์์ ๋ง์ด ์ฌ์ฉ๋จ |
5. ์ ์ ํ์ผ ๋ฑ๋ก
app.use(express.static(path.join(__dirname, "public")));
- CSS, ์ด๋ฏธ์ง, JS ํ์ผ์ฒ๋ผ ์ ์ ์์๋ค์ ์๋นํ๋ ํด๋๋ฅผ ์ค์ ํ๋ค.
publicํด๋ ์์ ์๋ ํ์ผ์ ๋ธ๋ผ์ฐ์ ์์ ์ง์ ์ ๊ทผ ๊ฐ๋ฅํ๋ค. (/style.css,/logo.png๋ฑ)
6. ๋ผ์ฐํฐ ๋ฑ๋ก
const contactsRoutes = require("./routes/contactsRoutes");
const loginRoutes = require("./routes/loginRoute");
app.use("/contacts", contactsRoutes);
app.use("/", loginRoutes);
โ ๋ผ์ฐํฐ(Router)๋?
**๋ผ์ฐํฐ(Router)**๋ ์ฌ์ฉ์์ ์์ฒญ URL๊ณผ HTTP ๋ฉ์๋(GET, POST ๋ฑ) ์ ๋ฐ๋ผ
์ด๋ค ์ฝ๋(์ปจํธ๋กค๋ฌ)๋ฅผ ์คํํ ์ง ์ ํด์ฃผ๋ ์ญํ
/contacts๋ก ์์ํ๋ ์์ฒญ์contactsRoutes.js์์ ์ฒ๋ฆฌํ๋ค./(๋ฃจํธ) ์์ฒญ์ ๋ก๊ทธ์ธ ๊ด๋ จ ๋ผ์ฐํ ์ ๋ด๋นํ๋loginRoute.js์์ ์ฒ๋ฆฌํ๋ค.
โ ๋ผ์ฐํฐ๋ฅผ ์ฐ๋ ์ด์ ?
| ์ด์ | ์ค๋ช |
|---|---|
| ์ฝ๋ ๋ถ๋ฆฌ | ๋ผ์ฐํ ๋ก์ง์ routes ํด๋์ ๋ฐ๋ก ์์ฑ ๊ฐ๋ฅ |
| ๊ฐ๋ ์ฑ ํฅ์ | ๊ฒฝ๋ก๋ณ๋ก ๊น๋ํ๊ฒ ์ ๋ฆฌ ๊ฐ๋ฅ |
| ์ ์ง๋ณด์ ์ฌ์ | ๊ธฐ๋ฅ๋ณ๋ก ํ์ผ์ด ๋ถ๋ฆฌ๋์ด ์์ ์ด ์ฌ์ |
๐ ๋ผ์ฐํฐ ํ์ผ์์ ์ ์๋ ์๋ ๊ฒฝ๋ก(/, /add, /123/edit ๋ฑ)๋ app.js์ use()์์ ์ง์ ํ ์ ๊ฒฝ๋ก์ ์๋์ผ๋ก ๋ถ๋๋ค.
7. ์๋ฒ ์คํ
app.listen(3000, () => {
console.log("์๋ฒ๊ฐ 3000๋ฒ ํฌํธ์์ ์คํ ์ค์
๋๋ค.");
});
- ๋ก์ปฌํธ์คํธ์์ ํฌํธ 3000๋ฒ์ผ๋ก ์๋ฒ๋ฅผ ์์ํ๋ค.
- ๋ธ๋ผ์ฐ์ ์์
http://localhost:3000์ผ๋ก ์ ์ํ๋ฉด ์๋น์ค๊ฐ ์์๋๋ค.
โ ๋ฐฐ์ด ๊ฐ๋ ๋ค ๋ฆฌ๋ง์ธ๋
| ๊ฐ๋ | ์ค๋ช |
|---|---|
req.body |
ํด๋ผ์ด์ธํธ๊ฐ form์ด๋ JSON์ผ๋ก ๋ณด๋ธ ๋ฐ์ดํฐ |
| ๋ฏธ๋ค์จ์ด | ์์ฒญ๊ณผ ์๋ต ์ฌ์ด์์ ์ค๊ฐ์ฒ๋ฆฌ ์ญํ |
.env |
์ค์ํ ์ค์ ๊ฐ(API ํค, DB URI ๋ฑ)์ ์จ๊ธฐ๊ธฐ ์ํ ํ์ผ |
EJS |
ํ ํ๋ฆฟ ์์ง (HTML์ JS ์ฝ์ ๊ฐ๋ฅ) |
๋ผ์ฐํฐ |
๊ฒฝ๋ก์ ๋ฐ๋ผ ์คํ๋๋ ์ฒ๋ฆฌ๊ธฐ ํจ์ |
๐ contactsRoutes.js โ ์ฐ๋ฝ์ฒ ๋ผ์ฐํ
๋ด๋น ํ์ผ
ํด๋น ํ์ผ์
/contacts๋ก ์์ํ๋ ๋ชจ๋ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๋ผ์ฐํ ์ ์ฉ ํ์ผ์ด๋ค.
๐ ์ ์ฒด ์ฝ๋
const express = require("express");
const router = express.Router();
const {
getAllContacts,
createContact,
getContact,
updateContact,
deleteContact,
addContactForm,
} = require("../controllers/contactController");
// ์ฐ๋ฝ์ฒ ์ ์ฒด ๋ชฉ๋ก ์กฐํ
router.get("/", getAllContacts);
// ์ฐ๋ฝ์ฒ ์ถ๊ฐ ํผ ๋ณด์ฌ์ฃผ๊ธฐ
router.get("/add", addContactForm);
// ์ฐ๋ฝ์ฒ ์ถ๊ฐ
router.post("/add", createContact);
// ํน์ ์ฐ๋ฝ์ฒ ์์ธ ๋ณด๊ธฐ (์์ ํผ)
router.get("/:id", getContact);
// ์ฐ๋ฝ์ฒ ์์
router.put("/:id", updateContact);
// ์ฐ๋ฝ์ฒ ์ญ์
router.delete("/:id", deleteContact);
module.exports = router;
โ ๋ผ์ฐํฐ๋?
๋ผ์ฐํฐ(Router)๋ ํน์ URL ๊ฒฝ๋ก์ ๋ฐ๋ผ ์คํํ **์ฒ๋ฆฌ ๋ก์ง(์ปจํธ๋กค๋ฌ ํจ์)**์ ์ง์ ํด์ฃผ๋ ์ญํ ์ ํ๋ค.
์:
/contactsโ ์ ์ฒด ์ฐ๋ฝ์ฒ ์กฐํ/contacts/addโ ํผ ๋ณด์ฌ์ฃผ๊ธฐ / ์ถ๊ฐํ๊ธฐ/contacts/:idโ ์์ / ์ญ์
๐ app.js์ ์ฐ๊ฒฐ ๊ตฌ์กฐ ๋ณต์ต
// app.js
const contactsRoutes = require("./routes/contactsRoutes");
app.use("/contacts", contactsRoutes);
- ์ด ์ค์ ์ผ๋ก ์ธํด
contactsRoutes.js๋ด๋ถ์"/"๋ ์ค์ ๋ก๋/contacts๊ฒฝ๋ก๋ฅผ ์๋ฏธํ๋ค. - ์ฆ,
router.get("/")๋ ๊ฒฐ๊ตญGET /contacts๋ก ๋์ํ๋ค.
โ ์ฃผ์ ๋ผ์ฐํ
1. ์ ์ฒด ์ฐ๋ฝ์ฒ ๋ชฉ๋ก ์กฐํ
router.get("/", getAllContacts);
GET /contacts์์ฒญ ์ ์คํ- ์ปจํธ๋กค๋ฌ์
getAllContacts()ํจ์์์ DB ๋ฐ์ดํฐ๋ฅผ ์กฐํ ํindex.ejs์ ๋ ๋๋ง
2. ์ฐ๋ฝ์ฒ ์ถ๊ฐ ํผ ๋ณด์ฌ์ฃผ๊ธฐ
router.get("/add", addContactForm);
GET /contacts/add์์ฒญ ์ ์คํadd.ejsํผ ํ์ด์ง๋ฅผ ํด๋ผ์ด์ธํธ์๊ฒ ๋ ๋๋งํ๋ค.
3. ์ฐ๋ฝ์ฒ ์์ฑ (POST)
router.post("/add", createContact);
POST /contacts/add- ์ฌ์ฉ์๊ฐ ํผ์ ์ ๋ ฅํ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ MongoDB์ ์ ์ฅ
- ์ ์ฅ ํ
/contacts๋ก ๋ฆฌ๋๋ ์ ๋จ
โ req.body์ ์ ๋ณด๊ฐ ์ด๋ป๊ฒ ์ ๋ณด๊ฐ ๋ด๊ธธ๊น?
HTML
<form>์์ ์ ์ก๋ ๋ฐ์ดํฐ๋app.use(express.urlencoded())๋ฏธ๋ค์จ์ด๋ฅผ ํตํดreq.body์ ๋ค์ด๊ฐ๋ค.
4. ์ฐ๋ฝ์ฒ ์์ธ ์กฐํ (์์ ํผ)
router.get("/:id", getContact);
GET /contacts/:id(์:/contacts/123)- ํน์ ์ฐ๋ฝ์ฒ๋ฅผ ๋ถ๋ฌ์์
update.ejs์ ๋ ๋๋ง
โ /:id์ ์๋ฏธ๋?
๋ผ์ฐํ ๊ฒฝ๋ก์์ /:id์ ๊ฐ์ด ์ฝ๋ก (:) ์ ๋ถ์ด๋ฉด, โ์ฌ๊ธฐ์๋ ์ด๋ค ๊ฐ์ด๋ ๋ค์ด์ฌ ์ ์๋ค!โ ๋ผ๋ ๋ป
์ฆ, :id๋ ๋ณ์์ฒ๋ผ ๋์ํ๋ค.
์ฌ์ฉ์๊ฐ ์ ์ํ ๋๋ง๋ค ์ด ์๋ฆฌ์ ๋ค๋ฅธ ๊ฐ์ด ๋ค์ด์ค๊ฒ ๋๋ค.
๐งฉ ์์
router.get("/contacts/:id", getContact);
์ฌ์ฉ์๊ฐ /contacts/1234๋ก ์ ์ํ๋ฉด:
:id๋ โ1234โ๋ก ํด์๋จ
๊ฒฐ๊ณผ : req.params.id === โ1234โ
5. ์ฐ๋ฝ์ฒ ์์
router.put("/:id", updateContact);
PUT /contacts/:id- DB์์ ํด๋น ID์ ์ฐ๋ฝ์ฒ๋ฅผ ์์ ํจ
๐ ๊ด๋ จ ๊ฐ๋ :
PUT์์ฒญ์ HTML ํผ์์ ์ง์ ๋ณด๋ผ ์ ์๊ธฐ ๋๋ฌธ์ method-override ๋ชจ๋์ ์ฌ์ฉํ๋ค.<form method="POST" action="/contacts/<%= contact._id %>?_method=PUT">
โ
์ HTML ํผ์์๋ GET, POST๋ง ์ง์ํ ๊น?
HTML์ <form> ํ๊ทธ๋ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ๋ค:
<form action="/update" method="POST">
<!-- ์
๋ ฅ ํ๋๋ค -->
</form>
์ด๋ method="POST" ํน์ method="GET"๋ง ์ธ ์ ์๋ค.
๐ ์ด์ :
HTML ํ์ค(์คํ)์์ <form> ํ๊ทธ๋ ์ค์ง GET๊ณผ POST๋ง ์ง์ํ๋๋ก ์ ์๋์ด ์๊ธฐ ๋๋ฌธ
์ฆ, HTML ์์ฒด๊ฐ PUT, DELETE ์์ฒญ์ ์ ์กํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง ์๋๋ค.
โ ๊ทธ๋ผ PUT/DELETE์ ์ธ์ ์ฌ์ฉ ๊ฐ๋ฅํ ๊น?
RESTful API๋ฅผ ๋ง๋ค ๋๋ ์ด๋ฐ ๋ฐฉ์์ด ์ผ๋ฐ์ ์ด๋ค.
| ์์ฒญ ๋ฐฉ์ | ์ค๋ช |
|---|---|
| GET | ๋ฐ์ดํฐ ์กฐํ |
| POST | ์ ๋ฐ์ดํฐ ์ถ๊ฐ |
| PUT | ๋ฐ์ดํฐ ์์ |
| DELETE | ๋ฐ์ดํฐ ์ญ์ |
์ฆ, ๋ฐฑ์๋์์๋ PUT์ด๋ DELETE๊ฐ ํ์ํ๋ฐ,
HTML์ ๊ทธ๊ฑธ ๋ชป ๋ณด๋ด๋๊น ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด ํ์ํ๋ค.
โ
ํด๊ฒฐ ๋ฐฉ๋ฒ: method-override ๋ชจ๋
method-override๋ POST ์์ฒญ์ โ๊ฐ์ง๋กโ PUT์ด๋ DELETE์ฒ๋ผ ๋ฐ๊ฟ์ฃผ๋ ๋ฏธ๋ค์จ์ด์ด๋ค.
๐ ์ฌ์ฉ ๋ฐฉ๋ฒ
HTML:
<form action="/contacts/123?_method=PUT" method="POST">
<!-- ์
๋ ฅ ํ๋ -->
</form>
์๋ฒ :
const methodOverride = require("method-override");
app.use(methodOverride("_method"));
โ ๋์ ๋ฐฉ์:
- HTML์ ์ด์ฉ ์ ์์ด POST๋ก ์์ฒญ์ ๋ณด๋
- ๊ทธ๋ฐ๋ฐ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ก
_method=PUT์ ์ถ๊ฐ - ์๋ฒ์์
method-override๊ฐ_method๊ฐ์ ์ฝ๊ณ , PUT์ผ๋ก ๋ณ๊ฒฝ
โ ์์ฝ
| ๊ตฌ๋ถ | ์ค๋ช |
|---|---|
HTML <form> ์ง์ ๋ฐฉ์ |
GET, POST๋ง ๊ฐ๋ฅ |
PUT, DELETE ์ฌ์ฉ ๋ชฉ์ |
RESTful ์ค๊ณ์์ ์์ /์ญ์ ๋ฅผ ์ํด ํ์ |
| ํด๊ฒฐ ๋ฐฉ๋ฒ | method-override ๋ฏธ๋ค์จ์ด๋ก ํด๊ฒฐ |
6. ์ฐ๋ฝ์ฒ ์ญ์
router.delete("/:id", deleteContact);
DELETE /contacts/:id- ํด๋น ID์ ์ฐ๋ฝ์ฒ๋ฅผ DB์์ ์ญ์
๐ ๊ด๋ จ ๊ฐ๋ :
- ๋ง์ฐฌ๊ฐ์ง๋ก HTML์์๋
DELETE์์ฒญ์ ์ง์ ๋ชป ๋ณด๋ด๊ธฐ ๋๋ฌธ์method-override๋ฅผ ํ์ฉํ๋ค.
๐ ์ต์ข ์ ๋ฆฌ: ์ฒ๋ฆฌ ํ๋ฆ
| ์์ฒญ URL | HTTP ๋ฉ์๋ | ์คํ ํจ์ |
|---|---|---|
/contacts |
GET | getAllContacts |
/contacts/add |
GET | addContactForm |
/contacts/add |
POST | createContact |
/contacts/:id |
GET | getContact |
/contacts/:id |
PUT | updateContact |
/contacts/:id |
DELETE | deleteContact |
โ ๋ฐฐ์ด ๊ฐ๋ ๋ค ๋ฆฌ๋ง์ธ๋
| ๊ฐ๋ | ์ค๋ช |
|---|---|
| ๋ผ์ฐํฐ | URL ์์ฒญ ๊ฒฝ๋ก์ ์ฒ๋ฆฌ ๋ก์ง(์ปจํธ๋กค๋ฌ ํจ์)์ ์ฐ๊ฒฐํ๋ ์ญํ |
router.get() |
GET ์์ฒญ (๋ฐ์ดํฐ ์กฐํ) |
router.post() |
POST ์์ฒญ (๋ฐ์ดํฐ ์์ฑ) |
router.put() |
PUT ์์ฒญ (๋ฐ์ดํฐ ์์ ) |
router.delete() |
DELETE ์์ฒญ (๋ฐ์ดํฐ ์ญ์ ) |
:id |
๋ผ์ฐํธ ๋งค๊ฐ๋ณ์. URL์์ ID ๊ฐ์ ์ถ์ถํ ์ ์์ |
๐ contactController.js โ ์ฐ๋ฝ์ฒ ๊ด๋ จ ๋น์ฆ๋์ค ๋ก์ง ๋ด๋น
์ปจํธ๋กค๋ฌ๋ ์์ฒญ์ด ๋ค์ด์์ ๋ ์ค์ ๋์์ ์ ์ํ ํจ์๋ค์ ์งํฉ
๐ ์ ์ฒด ์ฝ๋
const asyncHandler = require("express-async-handler");
const Contact = require("../models/contactModel");
// ์ฐ๋ฝ์ฒ ์ ์ฒด ์กฐํ
const getAllContacts = asyncHandler(async (req, res) => {
const contacts = await Contact.find();
res.render("index", { contacts });
});
// ์ฐ๋ฝ์ฒ ์ถ๊ฐ ํผ ๋ ๋๋ง
const addContactForm = (req, res) => {
res.render("add");
};
// ์ฐ๋ฝ์ฒ ์ถ๊ฐ
const createContact = asyncHandler(async (req, res) => {
const { name, email, phone } = req.body;
if (!name || !email || !phone) {
return res.send("ํ์ ๊ฐ์ด ์
๋ ฅ๋์ง ์์์ต๋๋ค.");
}
await Contact.create({ name, email, phone });
res.redirect("/contacts");
});
// ํน์ ์ฐ๋ฝ์ฒ ์กฐํ (์์ ํผ ๋ ๋๋ง)
const getContact = asyncHandler(async (req, res) => {
const contact = await Contact.findById(req.params.id);
res.render("update", { contact });
});
// ์ฐ๋ฝ์ฒ ์์
const updateContact = asyncHandler(async (req, res) => {
await Contact.findByIdAndUpdate(req.params.id, req.body, {
new: true, // ์
๋ฐ์ดํธ๋ ๋ฐ์ดํฐ ๋ฐํ
});
res.redirect("/contacts");
});
// ์ฐ๋ฝ์ฒ ์ญ์
const deleteContact = asyncHandler(async (req, res) => {
await Contact.findByIdAndDelete(req.params.id);
res.redirect("/contacts");
});
module.exports = {
getAllContacts,
addContactForm,
createContact,
getContact,
updateContact,
deleteContact,
};
โ ์ปจํธ๋กค๋ฌ๋?
์ปจํธ๋กค๋ฌ๋ ๋ผ์ฐํฐ์์ ์ฐ๊ฒฐ๋ ํจ์๋ค์ ์ค์ ๋์์ ๋ด๋นํ๋ ๊ณณ
์ฆ, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ๋ค์ด์์ ๋ ๋ฌด์จ ์์ ์ ํ ์ง ์ ์๋ ์คํ ๋ก์ง
์) ์ฌ์ฉ์๊ฐ /contacts๋ก ์ ์ํ๋ฉด ์ ์ฒด ๋ชฉ๋ก์ ๋ณด์ฌ์ฃผ๊ฑฐ๋, /contacts/add๋ก ์ ์ํ๋ฉด ์
๋ ฅ ํผ์ ๋ณด์ฌ์ฃผ๋ ๋ฑ
โ ํจ์๋ณ ์ค๋ช
1. ์ ์ฒด ์ฐ๋ฝ์ฒ ์กฐํ - getAllContacts
const getAllContacts = asyncHandler(async (req, res) => {
const contacts = await Contact.find();
res.render("index", { contacts });
});
๐ ์ค๋ช :
Contact.find()๋ฅผ ํตํด ๋ชจ๋ ์ฐ๋ฝ์ฒ ๋ฐ์ดํฐ๋ฅผ MongoDB์์ ๊ฐ์ ธ์จ๋ค.- ๊ทธ ๊ฒฐ๊ณผ๋ฅผ
index.ejs์ ์ ๋ฌํด์ ๋ ๋๋ง
๐ก ๊ด๋ จ ๊ฐ๋ :
render("index", { contacts }):contacts๋ฐ์ดํฐ๋ฅผ EJS ํ์ผ์ ๋๊นasyncHandler: ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ์๋ํํด์ฃผ๋ ๋ฏธ๋ค์จ์ด ํจ์
2. ์ฐ๋ฝ์ฒ ์ถ๊ฐ ํผ - addContactForm
const addContactForm = (req, res) => {
res.render("add");
};
- ํด๋ผ์ด์ธํธ๊ฐ
GET /contacts/add๋ก ์์ฒญํ๋ฉดadd.ejsํ ํ๋ฆฟ์ ๋ ๋๋ง
3. ์ฐ๋ฝ์ฒ ์ถ๊ฐ ์ฒ๋ฆฌ - createContact
const createContact = asyncHandler(async (req, res) => {
const { name, email, phone } = req.body;
if (!name || !email || !phone) {
return res.send("ํ์ ๊ฐ์ด ์
๋ ฅ๋์ง ์์์ต๋๋ค.");
}
await Contact.create({ name, email, phone });
res.redirect("/contacts");
});
๐ ์ค๋ช :
req.body: ํผ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ด (form์์์์ ์ ์ก๋จ)- ์ ํจ์ฑ ๊ฒ์ฌ๋ก ๊ฐ์ด ๋น์ด์์ผ๋ฉด ๋ฉ์์ง ์ถ๋ ฅ
Contact.create()๋ฅผ ํตํด DB์ ๋ฐ์ดํฐ ์ ์ฅ- ์ ์ฅ ์๋ฃ ํ
/contacts๋ก ๋ฆฌ๋๋ ์
๐ก ๊ด๋ จ ๊ฐ๋ :
redirect("/contacts"): ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์๊ฒ ๋ค๋ฅธ URL๋ก ์ด๋ํ๋ผ๊ณ ์ง์
4. ์์ ํผ ๋ถ๋ฌ์ค๊ธฐ - getContact
const getContact = asyncHandler(async (req, res) => {
const contact = await Contact.findById(req.params.id);
res.render("update", { contact });
});
๐ ์ค๋ช :
- URL์ ์๋
:id๊ฐ์ ํตํด DB์์ ํด๋น ์ฐ๋ฝ์ฒ ์ ๋ณด๋ฅผ ์กฐํ update.ejsํ์ด์ง์ ํด๋น ์ฐ๋ฝ์ฒ ๋ฐ์ดํฐ๋ฅผ ๋๊ฒจ์ค
๐ก ๊ด๋ จ ๊ฐ๋ :
req.params.id: URL์/:id๋ถ๋ถ์์ ๊ฐ ์ถ์ถ
5. ์ฐ๋ฝ์ฒ ์์ ์ฒ๋ฆฌ - updateContact
const updateContact = asyncHandler(async (req, res) => {
await Contact.findByIdAndUpdate(req.params.id, req.body, {
new: true,
});
res.redirect("/contacts");
});
๐ ์ค๋ช :
- ์์ ๋ ๋ฐ์ดํฐ๋ฅผ DB์ ๋ฐ์
new: true: ์์ ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๊ฒ ์ค์ - ์์ ํ
/contacts๋ก ๋ฆฌ๋๋ ์
6. ์ฐ๋ฝ์ฒ ์ญ์ - deleteContact
const deleteContact = asyncHandler(async (req, res) => {
await Contact.findByIdAndDelete(req.params.id);
res.redirect("/contacts");
});
๐ ์ค๋ช :
req.params.id๋ก ํด๋น ์ฐ๋ฝ์ฒ๋ฅผ ์ฐพ์์ ์ญ์ - ์ญ์ ์๋ฃ ํ
/contacts๋ก ๋ฆฌ๋๋ ์
โ ๊ด๋ จ ๊ฐ๋ ์ ๋ฆฌ
| ๊ฐ๋ | ์ค๋ช |
|---|---|
asyncHandler |
๋น๋๊ธฐ ํจ์์์ try-catch ์์ด ์๋ฌ๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํด์ฃผ๋ ํจ์ |
req.body |
ํด๋ผ์ด์ธํธ์์ ๋ณด๋ธ ํผ(form) ๋ฐ์ดํฐ |
res.render() |
EJS ํ ํ๋ฆฟ ๋ ๋๋ง (ํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ธฐ) |
res.redirect() |
๋ค๋ฅธ ํ์ด์ง๋ก ์ด๋ (URL ๋ณ๊ฒฝ) |
findById, create, update, delete |
Mongoose์ MongoDB ์กฐ์ ๋ฉ์๋ |
new: true |
์ ๋ฐ์ดํธ ํ ๋ฐ๋ ๊ฐ์ ๋ฐํํ๋๋ก ์ค์ |
๐ loginRoute.js โ ๋ก๊ทธ์ธ ๋ฐ ํ์๊ฐ์ ๋ผ์ฐํฐ
๋ผ์ฐํฐ๋ ์ฌ์ฉ์๊ฐ ํน์ URL์ ์ ๊ทผํ์ ๋ ์ด๋ค ์ปจํธ๋กค๋ฌ ํจ์๊ฐ ์คํ๋ ์ง๋ฅผ ์ง์ ํด์ฃผ๋ ์ญํ ์ ํ๋ค.
๐ ์ ์ฒด ์ฝ๋
const express = require("express");
const {
getLogin,
loginUser,
getRegister,
registerUser,
} = require("../controllers/loginController");
const router = express.Router();
// ๐ ๋ก๊ทธ์ธ ๊ด๋ จ ๋ผ์ฐํ
router.get("/", getLogin); // ๋ก๊ทธ์ธ ํผ
router.post("/", loginUser); // ๋ก๊ทธ์ธ ์์ฒญ ์ฒ๋ฆฌ
// ๐ ํ์๊ฐ์
๊ด๋ จ ๋ผ์ฐํ
router.get("/register", getRegister); // ํ์๊ฐ์
ํผ
router.post("/register", registerUser); // ํ์๊ฐ์
์์ฒญ ์ฒ๋ฆฌ
module.exports = router;
โ ๊ฒฝ๋ก๋ณ ๋ผ์ฐํ ์ค๋ช
1. router.get("/") โ ๋ก๊ทธ์ธ ํผ
- ์ฌ์ฉ์๊ฐ ๋ฃจํธ ๊ฒฝ๋ก
/์ ์ ์ํ๋ฉดhome.ejs๋ก๊ทธ์ธ ํผ์ ๋ณด์ฌ์ค๋ค. - ์ฐ๊ฒฐ๋ ์ปจํธ๋กค๋ฌ ํจ์:
getLogin
2. router.post("/") โ ๋ก๊ทธ์ธ ์์ฒญ ์ฒ๋ฆฌ
- ๋ก๊ทธ์ธ ํผ์์ POST ์์ฒญ์ด ๋ค์ด์ฌ ๊ฒฝ์ฐ
- username, password๋ฅผ ํ์ธํ๊ณ JWT ํ ํฐ์ ๋ฐ๊ธํ๋ค.
- ์ฐ๊ฒฐ๋ ์ปจํธ๋กค๋ฌ ํจ์:
loginUser
3. router.get("/register") โ ํ์๊ฐ์
ํผ
/register๋ก ์ ์ํ๋ฉดregister.ejs๋ฅผ ๋ณด์ฌ์ค๋ค.- ์ฐ๊ฒฐ๋ ์ปจํธ๋กค๋ฌ ํจ์:
getRegister
4. router.post("/register") โ ํ์๊ฐ์
์ฒ๋ฆฌ
- ํ์๊ฐ์ ํผ์์ POST ์์ฒญ ์ ์คํ๋๋ค.
- username, password๋ฅผ ๋ฐ์ DB์ ์๋ก์ด ์ฌ์ฉ์ ๋ฑ๋กํ๋ค.
- ์ฐ๊ฒฐ๋ ์ปจํธ๋กค๋ฌ ํจ์:
registerUser
โ
์ router.get("/")์ด ๋ฃจํธ ๊ฒฝ๋ก๋ฅผ ์๋ฏธํ ๊น?
- ์ด ๋ผ์ฐํฐ ํ์ผ์
app.js์์app.use("/", loginRoutes)๋ก ๋ฑ๋ก๋์ด ์๊ธฐ ๋๋ฌธ์, - ์ค์ ๊ฒฝ๋ก
/์ ๋ฃจํธ ์ฃผ์(localhost:3000/)์ ํด๋นํ๊ฒ ๋๋ค.
๐ loginController.js โ ๋ก๊ทธ์ธ ๋ฐ ํ์๊ฐ์ ์ฒ๋ฆฌ ๋ก์ง
์ฌ์ฉ์์ ๋ก๊ทธ์ธ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ , JWT ํ ํฐ์ ๋ฐ๊ธํ๋ฉฐ, ํ์๊ฐ์ ์ ์ํธํ๋ฅผ ์ฒ๋ฆฌ
๐ ์ ์ฒด ์ฝ๋
const jwt = require("jsonwebtoken");
const bcrypt = require("bcryptjs");
const User = require("../models/userModel");
require("dotenv").config();
const jwtSecret = process.env.JWT_SECRET;
// ๐ ๋ก๊ทธ์ธ ํผ ๋ ๋๋ง
const getLogin = (req, res) => {
res.render("home");
};
// ๐ ์ฌ์ฉ์ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ
const loginUser = async (req, res) => {
const { username, password } = req.body;
try {
const user = await User.findOne({ username });
if (!user) {
return res.status(401).send("โ ์ฌ์ฉ์ ์์");
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(401).send("โ ๋น๋ฐ๋ฒํธ๊ฐ ํ๋ ธ์ต๋๋ค.");
}
const token = jwt.sign({ id: user._id }, jwtSecret);
res.cookie("token", token, { httpOnly: true });
res.redirect("/contacts");
} catch (error) {
console.error(error);
res.status(500).send("์๋ฒ ์ค๋ฅ ๋ฐ์");
}
};
// ๐ธ ํ์๊ฐ์
ํผ ๋ ๋๋ง
const getRegister = (req, res) => {
res.render("register");
};
// ๐ธ ํ์๊ฐ์
์ฒ๋ฆฌ
const registerUser = async (req, res) => {
const { username, password, password2 } = req.body;
if (password !== password2) {
return res
.status(400)
.json({ message: "โ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค." });
}
try {
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = await User.create({
username,
password: hashedPassword,
});
res.status(201).json({
message: "โ
ํ์๊ฐ์
์๋ฃ",
user: {
id: newUser._id,
username: newUser.username,
},
});
} catch (error) {
console.error(error);
res.status(500).json({ message: "โ ์๋ฒ ์ค๋ฅ๋ก ํ์๊ฐ์
์คํจ" });
}
};
module.exports = {
getLogin,
loginUser,
getRegister,
registerUser,
};
โ ํจ์๋ณ ์ค๋ช
1. ๋ก๊ทธ์ธ ํผ ๋ณด์ฌ์ฃผ๊ธฐ - getLogin
- ํ ํ๋ฉด(home.ejs)์ ๋ณด์ฌ์ฃผ๋ ์ญํ
GET /์์ฒญ์ ๋์- HTML ํผ์์
username,password์ ๋ ฅ
2. ๋ก๊ทธ์ธ ์ฒ๋ฆฌ - loginUser
๐ ์ค๋ช :
- DB์์
username์ ๊ธฐ์ค์ผ๋ก ์ฌ์ฉ์ ์ฐพ๊ธฐ - ๋น๋ฐ๋ฒํธ ๋น๊ต:
bcrypt.compare()์ฌ์ฉ - ์ผ์นํ๋ฉด JWT ํ ํฐ์ ๋ง๋ค์ด์ ์ฟ ํค์ ์ ์ฅ
- ๋ก๊ทธ์ธ ์ฑ๊ณต ์
/contacts๋ก ๋ฆฌ๋๋ ์
๐ก ๊ด๋ จ ๊ฐ๋ :
| ๊ฐ๋ | ์ค๋ช |
|---|---|
bcrypt.compare() |
ํ๋ฌธ ๋น๋ฐ๋ฒํธ์ ์ํธํ๋ ๋น๋ฐ๋ฒํธ ๋น๊ต |
jwt.sign() |
์ฌ์ฉ์ ์ ๋ณด๋ฅผ ํ ๋๋ก JWT ํ ํฐ ์์ฑ |
res.cookie("token", token) |
์์ฑํ ํ ํฐ์ ๋ธ๋ผ์ฐ์ ์ฟ ํค์ ์ ์ฅ |
res.redirect() |
ํน์ ํ์ด์ง๋ก ์ด๋ํ๋๋ก ์๋ต |
3. ํ์๊ฐ์
ํผ ๋ ๋๋ง - getRegister
- ํ์๊ฐ์ ์ ๋ ฅ ํผ(register.ejs)์ ๋ณด์ฌ์ค
4. ํ์๊ฐ์
์ฒ๋ฆฌ - registerUser
๐ ์ค๋ช :
- ๋น๋ฐ๋ฒํธ์ ๋น๋ฐ๋ฒํธ ํ์ธ์ด ์ผ์นํ๋์ง ๊ฒ์ฌ
bcrypt.hash()๋ก ๋น๋ฐ๋ฒํธ ์ํธํ- DB์ ์ฌ์ฉ์ ์ ๋ณด ์ ์ฅ
- JSON ์๋ต์ผ๋ก ๊ฒฐ๊ณผ ๋ฐํ
โ ์ง๋ฌธ
catch(error)๋ ์ด๋ค ์ํฉ์์ ์คํ๋ ๊น?
- ์์์ ์์ํ์ง ๋ชปํ ์๋ฒ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ ๋ ์คํ๋จ
- ์: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๋ฅ, bcrypt ์๋ฌ ๋ฑ
Q3. module.exports = { ... } ๋ ๋ญ๊น?
- ์ฌ๋ฌ ๊ฐ์ ํจ์๋ฅผ ๊ฐ์ฒด ํํ๋ก ์ธ๋ถ๋ก ๋ด๋ณด๋ธ๋ค.
- ์ธ๋ถ์์ ํด๋น ๋ชจ๋์ ์ํฌํธํ ๋ ๋ถ๋ฌ์ ์ฌ์ฉํ๋ ๊ฐ์ฒด๋ค์ ๋ชฉ๋ก
ํจ์์ ๋ชจ์์ด์ ํ๋์ ๋ชจ๋๋ก์ ๋ผ์ฐํฐ์์ ์ฌ์ฉ ๊ฐ๋ฅ
โ ๊ฐ๋ ์ ๋ฆฌ
| ๊ฐ๋ | ์ค๋ช |
|---|---|
| JWT ํ ํฐ | ์ธ์ฆ์ ์ํด ๋ฐ๊ธํ๋ ์ผํ์ฉ ์ํธ ํ ํฐ |
| ์ฟ ํค | ํด๋ผ์ด์ธํธ ๋ธ๋ผ์ฐ์ ์ ์ ์ฅ๋๋ ์์ ๋ฐ์ดํฐ ์กฐ๊ฐ |
| bcrypt | ๋น๋ฐ๋ฒํธ ์ํธํ ๋ชจ๋ |
| req.body | ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ POST ๋ฐ์ดํฐ |
| ์ปจํธ๋กค๋ฌ | ์์ฒญ ์ฒ๋ฆฌ์ ์ค์ ๋ก์ง์ด ๋ด๊ธด ํจ์๋ค |
| async/await | ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ฐฉ์ |
| try-catch | ์์ธ ์ฒ๋ฆฌ ๋ฐฉ์ |