Node.js ์‹ค์Šต ์ฝ”๋“œ ๋ณต๊ธฐ

์ด ๊ธ€์˜ ๋ชฉ์ฐจ75๊ฐœ
  1. ๐Ÿ“Œ ์‹ค์Šต ์†Œ๊ฐœ
  2. ๐Ÿงฉ ์‚ฌ์šฉ ๊ธฐ์ˆ  ์Šคํƒ
  3. ๐Ÿ“‚ ํด๋” ๊ตฌ์กฐ (์ค‘์š” ํŒŒ์ผ๋งŒ ์š”์•ฝ)
  4. ๐Ÿ”‘ ๊ตฌํ˜„๋œ ์ฃผ์š” ๊ธฐ๋Šฅ
  5. ๐Ÿง  ๋ฐฐ์šด ๊ฐœ๋…๋“ค
  6. ๐Ÿ“„ ์ „์ฒด ์ฝ”๋“œ
  7. โœ… ์ฝ”๋“œ ์„ค๋ช…
  8. 1. require() โ€” ๋ชจ๋“ˆ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
  9. ๐Ÿ“Œ ์งˆ๋ฌธ : require("dotenv").config();๋ž€?
  10. ๐Ÿ“Œ ์งˆ๋ฌธ : .env ํŒŒ์ผ์ด ๋ณดํ˜ธ๋ฐ›๋Š” ์›๋ฆฌ๋Š”?
  11. 2. dbConnect(); โ€” MongoDB ์—ฐ๊ฒฐ
  12. 3. ๋ฏธ๋“ค์›จ์–ด ์„ค์ •
  13. ๋ฏธ๋“ค์›จ์–ด(Middleware)๋ž€?
  14. 4. ๋ทฐ ํ…œํ”Œ๋ฆฟ ์„ค์ •
  15. โœ… EJS๋ž€?
  16. โœ… ์‚ฌ์šฉ ์ด์œ 
  17. โœ… ์ฃผ์š” ํŠน์ง•
  18. 5. ์ •์  ํŒŒ์ผ ๋“ฑ๋ก
  19. 6. ๋ผ์šฐํ„ฐ ๋“ฑ๋ก
  20. โœ… ๋ผ์šฐํ„ฐ(Router)๋ž€?
  21. โœ… ๋ผ์šฐํ„ฐ๋ฅผ ์“ฐ๋Š” ์ด์œ ?
  22. 7. ์„œ๋ฒ„ ์‹คํ–‰
  23. โœ… ๋ฐฐ์šด ๊ฐœ๋…๋“ค ๋ฆฌ๋งˆ์ธ๋“œ
  24. ๐Ÿ“„ ์ „์ฒด ์ฝ”๋“œ
  25. โœ… ๋ผ์šฐํ„ฐ๋ž€?
  26. ๐Ÿ”— app.js์™€ ์—ฐ๊ฒฐ ๊ตฌ์กฐ ๋ณต์Šต
  27. โœ… ์ฃผ์š” ๋ผ์šฐํŒ…
  28. 1. ์ „์ฒด ์—ฐ๋ฝ์ฒ˜ ๋ชฉ๋ก ์กฐํšŒ
  29. 2. ์—ฐ๋ฝ์ฒ˜ ์ถ”๊ฐ€ ํผ ๋ณด์—ฌ์ฃผ๊ธฐ
  30. 3. ์—ฐ๋ฝ์ฒ˜ ์ƒ์„ฑ (POST)
  31. โœ… req.body์— ์ •๋ณด๊ฐ€ ์–ด๋–ป๊ฒŒ ์ •๋ณด๊ฐ€ ๋‹ด๊ธธ๊นŒ?
  32. 4. ์—ฐ๋ฝ์ฒ˜ ์ƒ์„ธ ์กฐํšŒ (์ˆ˜์ • ํผ)
  33. โœ… /:id์˜ ์˜๋ฏธ๋Š”?
  34. ์ฆ‰, :id๋Š” ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ๋™์ž‘ํ•œ๋‹ค.
  35. ๐Ÿงฉ ์˜ˆ์‹œ
  36. 5. ์—ฐ๋ฝ์ฒ˜ ์ˆ˜์ •
  37. โœ… ์™œ HTML ํผ์—์„œ๋Š” GET, POST๋งŒ ์ง€์›ํ• ๊นŒ?
  38. ๐Ÿ“Œ ์ด์œ :
  39. โœ… ๊ทธ๋Ÿผ PUT/DELETE์€ ์–ธ์ œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ• ๊นŒ?
  40. โœ… ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: method-override ๋ชจ๋“ˆ
  41. ๐Ÿ“Œ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
  42. โœ… ๋™์ž‘ ๋ฐฉ์‹:
  43. โœ… ์š”์•ฝ
  44. 6. ์—ฐ๋ฝ์ฒ˜ ์‚ญ์ œ
  45. ๐Ÿ”„ ์ตœ์ข… ์ •๋ฆฌ: ์ฒ˜๋ฆฌ ํ๋ฆ„
  46. โœ… ๋ฐฐ์šด ๊ฐœ๋…๋“ค ๋ฆฌ๋งˆ์ธ๋“œ
  47. ๐Ÿ“„ ์ „์ฒด ์ฝ”๋“œ
  48. โœ… ์ปจํŠธ๋กค๋Ÿฌ๋ž€?
  49. โœ… ํ•จ์ˆ˜๋ณ„ ์„ค๋ช…
  50. 1. ์ „์ฒด ์—ฐ๋ฝ์ฒ˜ ์กฐํšŒ - getAllContacts
  51. 2. ์—ฐ๋ฝ์ฒ˜ ์ถ”๊ฐ€ ํผ - addContactForm
  52. 3. ์—ฐ๋ฝ์ฒ˜ ์ถ”๊ฐ€ ์ฒ˜๋ฆฌ - createContact
  53. 4. ์ˆ˜์ •ํผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ - getContact
  54. 5. ์—ฐ๋ฝ์ฒ˜ ์ˆ˜์ • ์ฒ˜๋ฆฌ - updateContact
  55. 6. ์—ฐ๋ฝ์ฒ˜ ์‚ญ์ œ - deleteContact
  56. โœ… ๊ด€๋ จ ๊ฐœ๋… ์ •๋ฆฌ
  57. ๐Ÿ“ loginRoute.js โ€” ๋กœ๊ทธ์ธ ๋ฐ ํšŒ์›๊ฐ€์ž… ๋ผ์šฐํ„ฐ
  58. ๐Ÿ“„ ์ „์ฒด ์ฝ”๋“œ
  59. โœ… ๊ฒฝ๋กœ๋ณ„ ๋ผ์šฐํŒ… ์„ค๋ช…
  60. 1. router.get("/") โ€” ๋กœ๊ทธ์ธ ํผ
  61. 2. router.post("/") โ€” ๋กœ๊ทธ์ธ ์š”์ฒญ ์ฒ˜๋ฆฌ
  62. 3. router.get("/register") โ€” ํšŒ์›๊ฐ€์ž… ํผ
  63. 4. router.post("/register") โ€” ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ
  64. โœ… ์™œ router.get("/")์ด ๋ฃจํŠธ ๊ฒฝ๋กœ๋ฅผ ์˜๋ฏธํ• ๊นŒ?
  65. ๐Ÿ“ loginController.js โ€” ๋กœ๊ทธ์ธ ๋ฐ ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ ๋กœ์ง
  66. ๐Ÿ“„ ์ „์ฒด ์ฝ”๋“œ
  67. โœ… ํ•จ์ˆ˜๋ณ„ ์„ค๋ช…
  68. 1. ๋กœ๊ทธ์ธ ํผ ๋ณด์—ฌ์ฃผ๊ธฐ - getLogin
  69. 2. ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ - loginUser
  70. 3. ํšŒ์›๊ฐ€์ž… ํผ ๋ Œ๋”๋ง - getRegister
  71. 4. ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ - registerUser
  72. โœ… ์งˆ๋ฌธ
  73. catch(error)๋Š” ์–ด๋–ค ์ƒํ™ฉ์—์„œ ์‹คํ–‰๋ ๊นŒ?
  74. Q3. module.exports = { ... } ๋Š” ๋ญ˜๊นŒ?
  75. โœ… ๊ฐœ๋… ์ •๋ฆฌ

๐Ÿ›  ์—ฐ๋ฝ์ฒ˜ ๊ด€๋ฆฌ ์›น์•ฑ (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

๐Ÿ”‘ ๊ตฌํ˜„๋œ ์ฃผ์š” ๊ธฐ๋Šฅ

  1. ๐Ÿ” ํšŒ์›๊ฐ€์ž… & ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ
    • bcrypt๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™”
    • JWT๋กœ ๋กœ๊ทธ์ธ ํ† ํฐ ๋ฐœ๊ธ‰
    • ์ฟ ํ‚ค์— ํ† ํฐ ์ €์žฅ
  2. ๐Ÿ“‡ ์—ฐ๋ฝ์ฒ˜ CRUD ๊ธฐ๋Šฅ
    • ์—ฐ๋ฝ์ฒ˜ ๋“ฑ๋ก, ๋ชฉ๋ก ์กฐํšŒ, ์ˆ˜์ •, ์‚ญ์ œ
    • MongoDB์— ์ €์žฅ
    • EJS ํ…œํ”Œ๋ฆฟ์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ
  3. ๐Ÿ›ก ๋ฏธ๋“ค์›จ์–ด, ๋ผ์šฐํŒ…, ์ปจํŠธ๋กค๋Ÿฌ ๋ถ„๋ฆฌ
    • 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์— ์—…๋กœ๋“œ๋˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์›์น™์ด๋‹ค.

โœ… ์ž์„ธํ•œ ์„ค๋ช…

  1. .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์ธ ๊ฒฝ์šฐ ์‚ฌ์šฉ๋œ๋‹ค.
  • express.urlencoded({ extended: true }) :
    • HTML form ๋ฐฉ์‹์œผ๋กœ ์ „๋‹ฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ req.body์— ๋„ฃ์–ด์ค€๋‹ค.
    • EJS์—์„œ <form method="POST"> ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํ•„์ˆ˜์ด๋‹ค.
  • 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 ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฐฉ์‹
์ „์ฒด ๊ธ€ ๋ณด๊ธฐ