๐ŸŽฏ Express๋ฅผ ์‚ฌ์šฉํ•œ CRUD API๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , HTTP ์ƒํƒœ ์ฝ”๋“œ ๊ฐœ๋…์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ“™ Today I Learned

Express API ๊ตฌํ˜„

๊ฐœ๋ณ„ ์‚ญ์ œ ์š”์ฒญ ( DELETE )

// ๊ฐœ๋ณ„ ์‚ญ์ œ ์š”์ฒญ (DELETE)
app.delete('/books/:id', (req, res) => {
  let { id } = req.params;
  id = parseInt(id);
  const book = db.get(id);

  if (!book) {
    res.json({
      message: `์š”์ฒญํ•˜์‹  ${id}๋ฒˆ์€ ์—†๋Š” ์ฑ…์ž…๋‹ˆ๋‹ค.`,
    });
  } else {
    db.delete(id);
    res.json({
      message: `${book.title} ์ฑ…์ด ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`,
    });
  }
});
  • ์ฑ…์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด "์š”์ฒญํ•˜์‹  id๋ฒˆ ์ฑ…์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • ์ฑ…์ด ์กด์žฌํ•˜๋ฉด db.delete(id)๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜๊ณ  "${book.title} ์ฑ…์ด ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค." ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ „์ฒด ์‚ญ์ œ ์š”์ฒญ ( DELETE )

// ์ „์ฒด ์‚ญ์ œ ์š”์ฒญ (DELETE)
app.delete('/books', (req, res) => {
  let msg = '';
  if (db.size >= 1) {
    db.clear();
    msg = '๋ชจ๋“  ์ฑ…์ด ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.';
  } else {
    msg = '์‚ญ์ œํ•  ์ฑ…์ด ์—†์Šต๋‹ˆ๋‹ค.';
  }

  res.json({
    message: msg,
  });
});
  • ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ, db.clear()๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ์‚ญ์ œํ•˜๊ณ , "๋ชจ๋“  ์ฑ…์ด ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค" ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, "์‚ญ์ œํ•  ์ฑ…์ด ์—†์Šต๋‹ˆ๋‹ค." ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋ณ„ ์ˆ˜์ • ์š”์ฒญ ( PUT )

// ๊ฐœ๋ณ„ ์ˆ˜์ • (PUT)
app.put('/books/:id', (req, res) => {
  let { id } = req.params;
  id = parseInt(id);

  const book = db.get(id);
  if (!book) {
    res.json({
      message: `์š”์ฒญํ•˜์‹  ${id}๋ฒˆ์€ ์—†๋Š” ์ฑ…์ž…๋‹ˆ๋‹ค.`,
    });
  } else {
    let existingTitle = book.title;
    let newTitle = req.body.title;
    bexistingTitle = newTitle;
    db.set(id, book);
    res.json({
      message: `${existingTitle} ์ฑ…์˜ ์ด๋ฆ„์ด ${newTitle} (์œผ)๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`,
    });
  }
});
  • ๋ณธ๋ž˜ ์ œ๋ชฉ์„ existingTitle ๋ณ€์ˆ˜์— ์ €์žฅํ•˜๊ณ , ์ƒˆ๋กœ์šด ์ œ๋ชฉ์„ newTitle์— ์ €์žฅํ•˜์—ฌ ๊ฐ’์„ ๋ฎ์–ด์”Œ์›๋‹ˆ๋‹ค.

  • db.set(id)๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ๊ณ , "existingTitle ์ฑ…์˜ ์ด๋ฆ„์ด newTitle (์œผ)๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค." ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.




๋ฆฌํŒฉํ† ๋ง (Refactoring)

์ฝ”๋“œ์˜ ๊ธฐ๋Šฅ์€ ์œ ์ง€ํ•˜๋ฉด์„œ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๊ฐœ์„ ํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค.

๐Ÿค” ์™œ ํ•„์š”ํ•œ ๊ฑธ๊นŒ?

  • ์ฝ”๋“œ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”
  • ์•ˆ์ •์„ฑ ํ–ฅ์ƒ

๋ฆฌํŒฉํ† ๋ง ์‹œ๊ธฐ

  • ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์ „ (ex. API URL ์„ค๊ณ„ ์ˆ˜์ •)

  • ๋™์ผํ•œ ์—๋Ÿฌ๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฐœ์ƒํ•  ๋•Œ

  • โš ๏ธ ๋ฐฐํฌ, ์šด์˜ ์ง์ „์—๋Š” ๊ธˆ์ง€




HTTP ์ƒํƒœ ์ฝ”๋“œ (HTTP response status code)

ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ„์˜ ์š”์ฒญ ๊ฒฐ๊ณผ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.


โœ… ์„ฑ๊ณต ์‘๋‹ต 2xx

200 ok

์š”์ฒญ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์—ˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. (GET, PUT, DELETE ์„ฑ๊ณต ์‹œ ์ฃผ๋กœ ์‚ฌ์šฉ)

201 Created

์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. (POST ์š”์ฒญ ์„ฑ๊ณต ์‹œ ์‚ฌ์šฉ)

204 No Content

์š”์ฒญ์ด ์„ฑ๊ณตํ–ˆ์ง€๋งŒ ๋ฐ˜ํ™˜ํ•  ๋‚ด์šฉ์ด ์—†์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. (DELETE ์š”์ฒญ ํ›„ ๊ฒฐ๊ณผ๊ฐ€ ํ•„์š” ์—†์„ ๋•Œ)


โŒ ํด๋ผ์ด์–ธํŠธ ์—๋Ÿฌ ์‘๋‹ต 4xx

400 Bad Request

ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์ด ์ž˜๋ชป๋จ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. (ex. ํ•„์ˆ˜ ํ•„๋“œ ๋ˆ„๋ฝ)

403 Forbidden

์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ์ดํ•ดํ–ˆ์ง€๋งŒ, ๊ถŒํ•œ์ด ์—†์–ด ๊ฑฐ๋ถ€๋จ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. (ex. ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€ ์ ‘๊ทผ ์ œํ•œ)

404 Not Found

: ์„œ๋ฒ„๊ฐ€ ์š”์ฒญํ•œ ํŽ˜์ด์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. (์ž˜๋ชป๋œ URL ์š”์ฒญ)


โŒ ์„œ๋ฒ„ ์—๋Ÿฌ ์‘๋‹ต 5xx

500 Internal Server Error

์„œ๋ฒ„์—์„œ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์˜ค๋ฅ˜ ๋ฐœ์ƒํ•œ ๊ฒƒ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

503 Service Unavailable

์„œ๋ฒ„๊ฐ€ ๊ณผ๋ถ€ํ•˜ ์ƒํƒœ์ด๊ฑฐ๋‚˜ ์œ ์ง€๋ณด์ˆ˜ ์ค‘์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.




โœ๏ธ ํ•œ ์ค„ ํšŒ๊ณ 

HTTP ์ƒํƒœ ์ฝ”๋“œ๋กœ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์š”์ฒญ ๊ฒฐ๊ณผ๋ฅผ ํ•œ ๋ˆˆ์— ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ์š”์†Œ๋กœ์„œ ์—ญํ• ์ด ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค.

profile
๐ŸŒฑ๊ฐœ๋ฐœ ๊ธฐ๋ก์žฅ

0๊ฐœ์˜ ๋Œ“๊ธ€