๐Ÿง  ํ’€์Šคํƒ์œผ๋กœ ์ „ํ™˜: ๋ฐฑ์—”๋“œ ๋ฐ REST API ๊ตฌ์ถ•

๋ฐœํ–‰: (2025๋…„ 12์›” 26์ผ ์˜คํ›„ 05:26 GMT+9)
6 min read
์›๋ฌธ: Dev.to

Source: Dev.to

Cover image for ๐Ÿง  Going Full Stack: Building the Backend & REST API

Hey fellow developers! ๐Ÿ‘‹
์•ˆ๋…•ํ•˜์„ธ์š”, ๊ฐœ๋ฐœ์ž ์—ฌ๋Ÿฌ๋ถ„! ๐Ÿ‘‹

In my last post I focused on upgrading the frontend UI and UX. It looked much better, but it still lacked the fullโ€‘stack feel of a real application. This post is all about the backend โ€” where things actually started getting serious.
์ง€๋‚œ ๊ธ€์—์„œ๋Š” ํ”„๋ก ํŠธ์—”๋“œ UI์™€ UX๋ฅผ ๊ฐœ์„ ํ•˜๋Š” ๋ฐ ์ง‘์ค‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ›จ์”ฌ ๋ณด๊ธฐ ์ข‹์•„์กŒ์ง€๋งŒ ์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ’€์Šคํƒ ๊ฐ๊ฐ์€ ์•„์ง ๋ถ€์กฑํ–ˆ์ฃ . ์ด๋ฒˆ ๊ธ€์€ ๋ฐฑ์—”๋“œ์— ๊ด€ํ•œ ๋‚ด์šฉ์œผ๋กœ, ๋ณธ๊ฒฉ์ ์œผ๋กœ ์ง„์ง€ํ•ด์ง€๊ธฐ ์‹œ์ž‘ํ•œ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

Why Adding a Backend Was Necessary

๋ฐฑ์—”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ–ˆ๋˜ ์ด์œ 

Initially I wanted a backend to practice and improve my backend skills. From the appโ€™s perspective, a backend was essential for:
์ฒ˜์Œ์—” ๋ฐฑ์—”๋“œ ์‹ค๋ ฅ์„ ์—ฐ์Šตํ•˜๊ณ  ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ๋ฐฑ์—”๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ์•ฑ ์ž…์žฅ์—์„œ ๋ฐฑ์—”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ํ•„์ˆ˜์˜€์Šต๋‹ˆ๋‹ค:

  • ๐Ÿ“š Large amounts of quote data
  • ๐Ÿ“š ๋ฐฉ๋Œ€ํ•œ ์ธ์šฉ๊ตฌ ๋ฐ์ดํ„ฐ
  • ๐Ÿค– Future AI scalability
  • ๐Ÿค– ํ–ฅํ›„ AI ํ™•์žฅ์„ฑ
  • ๐Ÿ—‚๏ธ Categoryโ€‘based filtering
  • ๐Ÿ—‚๏ธ ์นดํ…Œ๊ณ ๋ฆฌ ๊ธฐ๋ฐ˜ ํ•„ํ„ฐ๋ง

Handling all of this purely on the frontend would have been messy and unrealistic. With a backend the solution becomes clean and manageable.
์ด ๋ชจ๋“  ์ž‘์—…์„ ํ”„๋ก ํŠธ์—”๋“œ๋งŒ์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค๋ฉด ๋ณต์žกํ•˜๊ณ  ๋น„ํ˜„์‹ค์ ์ผ ์ˆ˜๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ๋ฅผ ๋‘๋ฉด ํ•ด๊ฒฐ์ฑ…์ด ๊น”๋”ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.

Backend Setup & Structure

๋ฐฑ์—”๋“œ ์„ค์ • ๋ฐ ๊ตฌ์กฐ

Stack
์Šคํƒ

  • Node.js + Express โ†’ REST API
  • Node.js + Express โ†’ REST API
  • MongoDB (Compass locally) โ†’ Database
  • MongoDB (๋กœ์ปฌ Compass) โ†’ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
  • Render โ†’ Backend deployment (more on this in the next post)
  • Render โ†’ ๋ฐฑ์—”๋“œ ๋ฐฐํฌ (๋‹ค์Œ ๊ธ€์—์„œ ์ž์„ธํžˆ ๋‹ค๋ฃน๋‹ˆ๋‹ค)

Project Structure

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

/
โ”œโ”€โ”€ index.html
โ”œโ”€โ”€ style.css
โ”œโ”€โ”€ script.js
โ”œโ”€โ”€ backend/
โ”‚   โ”œโ”€โ”€ server.js
โ”‚   โ””โ”€โ”€ models/
โ”‚       โ””โ”€โ”€ Quote.js
โ””โ”€โ”€ README.md

Schema Creation

์Šคํ‚ค๋งˆ ์ƒ์„ฑ

The core of the backend is the quote schema:
๋ฐฑ์—”๋“œ์˜ ํ•ต์‹ฌ์€ ์ธ์šฉ๊ตฌ ์Šคํ‚ค๋งˆ์ž…๋‹ˆ๋‹ค:

const quoteSchema = new mongoose.Schema({
  text: { type: String, required: true },
  author: { type: String, required: true },
  category: { type: String, required: true }
});

How it works
๋™์ž‘ ๋ฐฉ์‹

  1. A category button is clicked on the frontend.
    ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  2. A request is sent to the backend.
    ๋ฐฑ์—”๋“œ์— ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.
  3. The backend filters quotes by category.
    ๋ฐฑ์—”๋“œ๊ฐ€ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„๋กœ ์ธ์šฉ๊ตฌ๋ฅผ ํ•„ํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค.
  4. The text and author are sent back.
    ํ…์ŠคํŠธ์™€ ์ €์ž๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  5. The quote is displayed to the user.
    ์ธ์šฉ๊ตฌ๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

Connecting Backend to Frontend

๋ฐฑ์—”๋“œ์™€ ํ”„๋ก ํŠธ์—”๋“œ ์—ฐ๊ฒฐ

Inside script.js (formerly index.js) I created a fetchQuotes() function:
script.js(์ด์ „ index.js) ์•ˆ์— fetchQuotes() ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค:

async function fetchQuotes(category = null) {
  try {
    const url = category
      ? `${API_URL}/quotes/category/${category}`
      : `${API_URL}/quotes`;

    const res = await fetch(url);
    const quotes = await res.json();

    usedQuotes = [];
    usedColours = [];
    newQuote();
  } catch (err) {
    console.error("Backend not available:", err);
  }
}

fetchQuotes();

For now API_URL points to localhost. Later it will switch to the deployed backend URL, which leads perfectly into the next post.
ํ˜„์žฌ API_URL์€ localhost๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ถ”ํ›„ ๋ฐฐํฌ๋œ ๋ฐฑ์—”๋“œ URL๋กœ ๋ฐ”๋€” ์˜ˆ์ •์ด๋ฉฐ, ์ด๋Š” ๋‹ค์Œ ๊ธ€๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

Final Result (Locally)

์ตœ์ข… ๊ฒฐ๊ณผ (๋กœ์ปฌ)

Everything works perfectly on my local system:
๋‚ด ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ ๋ชจ๋“  ๊ฒƒ์ด ์™„๋ฒฝํžˆ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค:

  • Quotes are fetched from the backend.
    ์ธ์šฉ๊ตฌ๊ฐ€ ๋ฐฑ์—”๋“œ์—์„œ ๊ฐ€์ ธ์™€์ง‘๋‹ˆ๋‹ค.
  • Categories are filtered correctly.
    ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ•„ํ„ฐ๋ง๋ฉ๋‹ˆ๋‹ค.
  • No more hardโ€‘coded data.
    ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋” ์ด์ƒ ์—†์Šต๋‹ˆ๋‹ค.

All thatโ€™s left is deployment.
์ด์ œ ๋‚จ์€ ๊ฒƒ์€ ๋ฐฐํฌ๋ฟ์ž…๋‹ˆ๋‹ค.

Whatโ€™s Coming Next

๋‹ค์Œ์— ๋‹ค๋ฃฐ ๋‚ด์šฉ

In the next post Iโ€™ll cover:
๋‹ค์Œ ๊ธ€์—์„œ๋Š” ๋‹ค์Œ์„ ๋‹ค๋ฃฐ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค:

  • ๐ŸŒ Frontend deployment โ†’ GitHub Pages
  • ๐ŸŒ ํ”„๋ก ํŠธ์—”๋“œ ๋ฐฐํฌ โ†’ GitHub Pages
  • โ˜๏ธ Backend deployment โ†’ Render
  • โ˜๏ธ ๋ฐฑ์—”๋“œ ๋ฐฐํฌ โ†’ Render
  • ๐Ÿงช Liveโ€‘data debugging
  • ๐Ÿงช ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๋””๋ฒ„๊น…
  • ๐Ÿ”„ MongoDB Compass โ†’ MongoDB Atlas
  • ๐Ÿ”„ MongoDB Compass โ†’ MongoDB Atlas

Stay tuned for the next update! ๐Ÿ˜„๐Ÿ”ฅ
๋‹ค์Œ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ธฐ๋Œ€ํ•ด ์ฃผ์„ธ์š”! ๐Ÿ˜„๐Ÿ”ฅ

Back to Blog

๊ด€๋ จ ๊ธ€

๋” ๋ณด๊ธฐ ยป

Java ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž ๊ณผ์ •: ์—”๋“œโ€‘ํˆฌโ€‘์—”๋“œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์ถ•

Java Full Stack Developer๋ž€ ๋ฌด์—‡์ธ๊ฐ€? Java Full Stack Developer๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชจ๋“  ๋ ˆ์ด์–ด์—์„œ ์ž‘์—…ํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ด๋‹ค. ์—ฌ๊ธฐ์—๋Š” ํ”„๋ก ํŠธโ€‘์—”๋“œ ๊ธฐ์ˆ โ€ฆ

GraphQL, React, Express์™€ ํ•จ๊ป˜ ํ˜„๋Œ€์ ์ธ ํ’€์Šคํƒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์ถ•

์™œ GraphQL, React, ๊ทธ๋ฆฌ๊ณ  Express๋ฅผ ์„ ํƒํ•ด์•ผ ํ• ๊นŒ? GraphQL, React, ๊ทธ๋ฆฌ๊ณ  Express๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ’€์Šคํƒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•˜๋ฉด ์—ฌ๋Ÿฌ ์‹ค์šฉ์ ์ธ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค: - ํšจ์œจ์ ์ธ ๋ฐ์ดํ„ฐโ€ฆ

์™œ GraphQL์€ ๋Œ€์ค‘ํ™”์— ์–ด๋ ค์›€์„ ๊ฒช๊ณ  ์žˆ์„๊นŒ? Under-Design์ธ๊ฐ€ Over-Design์ธ๊ฐ€?

I. GraphQL ์„œ๋น„์Šค ๊ฐœ๋ฐœ ๊ฐ„์†Œํ™” Zhipu Qingyan AI์—๊ฒŒ getBookById ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ GraphQL ์˜ˆ์ œ๋ฅผ ์ž‘์„ฑํ•ด ๋‹ฌ๋ผ๊ณ  ์š”์ฒญํ•˜๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค...