๐ง ํ์คํ์ผ๋ก ์ ํ: ๋ฐฑ์๋ ๋ฐ REST API ๊ตฌ์ถ
Source: Dev.to

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
๋์ ๋ฐฉ์
- A category button is clicked on the frontend.
ํ๋ก ํธ์๋์์ ์นดํ ๊ณ ๋ฆฌ ๋ฒํผ์ ํด๋ฆญํฉ๋๋ค. - A request is sent to the backend.
๋ฐฑ์๋์ ์์ฒญ์ ๋ณด๋ ๋๋ค. - The backend filters quotes by category.
๋ฐฑ์๋๊ฐ ์นดํ ๊ณ ๋ฆฌ๋ณ๋ก ์ธ์ฉ๊ตฌ๋ฅผ ํํฐ๋งํฉ๋๋ค. - The text and author are sent back.
ํ ์คํธ์ ์ ์๋ฅผ ๋ฐํํฉ๋๋ค. - 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! ๐๐ฅ
๋ค์ ์
๋ฐ์ดํธ๋ฅผ ๊ธฐ๋ํด ์ฃผ์ธ์! ๐๐ฅ