[ํด๋ผ์ฐ๋ฉ ์ดํ๋ฆฌ์ผ์ด์ ์์ง๋์ด๋ง TIL] 240415 - ํด๋ผ์ฐ๋ ์ปดํจํ & Firebase
Intro
์ด์ ์ API ํ์ต์ ํตํด ๋ฐ์ดํฐ๋ฅผ CRUDํ๋ ์ฝ๋๋ฅผ ์์ฑํ์๋๋ฐ ์ด๋ฒ ์๊ฐ์ ์์ฑ๋ ๋ฐ์ดํฐ๋ฅผ ์ง์ Firebase ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๋ ๋ฒ์ ๋ฐฐ์ฐ๊ณ ์ค์ตํ์๋ค.
์ค๋ ํ์ตํ ๋ด์ฉ
ํธ์คํ (Hosting)
: ํด๋ผ์ฐ๋๊ฐ ์์ฉํ ๋๊ธฐ ์ ๋ถํฐ ์ฌ์ฉํ๋ ์๋น์ค
ํธ์คํ vs ํด๋ผ์ฐ๋
ํธ์คํ ๊ณผ ํด๋ผ์ฐ๋๋ ์ปดํจํฐ ์์์ ๋น๋ ค ์ฌ์ฉํ๋ค๋ ๊ณตํต์ ์ ๊ฐ๊ณ ์๋ค.
์ด์๋น์ฉ๊ณผ ๊ด๋ฆฌ ํธ์์ฑ, ํ์ฅ์ฑ์ ์ฐจ์ด๊ฐ ์๋ค.
ํธ์คํ ์๋น์ค๋ ๋ฌผ๋ฆฌ์ ์ธ ์์์ ์๋ํ๋ ๊ฒ์ผ๋ก ์ฆ๊ฐ์ ์ธ ๋์์ ์ด๋ ค์์ด ์๋ค.
๋น์ฉ์ ๋งค์/๋ ๊ณ ์ ์ ์ด๋ค.
๊ธฐ๋ณธ์ ์ธ ์ธํ๋ผ (๋ฐฉํ๋ฒฝ, ๋คํธ์ํฌ ๋ฑ)๋ ํธ์คํ ์ ์ฒด์์ ์ง์ ๊ด๋ฆฌํ๋ค.
ํด๋ผ์ฐ๋ ์๋น์ค๋ ๋ ผ๋ฆฌ์ ๊ฐ์ ์์์ ์๋ํ๋ ๊ฒ์ด๋ค.
์คํ ๋ฆฌ์ง ์ฉ๋, ์ธ์คํด์ค ์ ์ฆ๊ฐ ๋ฑ ๋น ๋ฅธ ๋์์ด ๊ฐ๋ฅํ๊ณ ์ฌ์ฉํ๋ ๋งํผ ๋น์ฉ์ ์ง๋ถํ๊ฒ ๋๋ค.
์๋น์ค ์ด์์ ์ํ ์ธํ๋ผ๋ ์ง์ ๊ตฌ์ถํด์ผ ํ๋ค๋ ์ ์ด ํธ์คํ ๊ณผ์ ์ฐจ์ด์ ์ด๋ค.
ํด๋ผ์ฐ๋ ์๋น์ค ์ ํ
- IaaS (Infrastructure as a Service)
- Amazon Web Service
- Microsoft Azure
- Google Cloud
- IBM Cloud
- Oracle Cloud
- PaaS (Platform as a Service) : ์์ ๊ท๋ชจ์์ ์ ๋ฆฌํจ
- Vercel
- Netlify
- Heroku
- Firebase
- SaaS (Software as a Service)
- Notion
- Slack
- Google Workspace
- Microsoft 365
Firebase์ AWS
Firebase๋ PaaS ํด๋ผ์ฐ๋ ์๋น์ค๋ก ๋ชจ๋ฐ์ผ, ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ํนํ๋์ด ์๋ค.
๊ฐ๋จํด์ ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์ ์ง์ค์ด ๊ฐ๋ฅํ๋ฉฐ ๋น ๋ฅธ ๊ฐ๋ฐ๊ณผ ๋ฐฐํฌ๊ฐ ๊ฐ๋ฅํ ์ฅ์ ์ด ์๋ค.
ํฐ ๊ท๋ชจ์ ํ๋ก์ ํธ์์๋ ์๋น์ค ์ํคํ ์ฒ์ ํ์ฅ์ด ์ ํ๋๊ฑฐ๋, ๋น์ฉ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค.
AWS๋ IaaS ํด๋ผ์ฐ๋ ์๋น์ค์ด๋ฉฐ, ์ ๊ณ ์ ์ ์จ 1์์ธ ๊ด๋ฒ์ํ ํด๋ผ์ฐ๋ ์๋น์ค์ด๋ค.
๋๋ถ๋ถ์ ์๋น์ค ์๊ตฌ์ฌํญ์ ์ปค๋ฒ ๊ฐ๋ฅํ๋ฉฐ AWS๋ด ์ธํ๋ผ๋ฅผ ํ์ฉํด ๋์์ด ํ์ฅ์ด ๊ฐ๋ฅํ๋ค.
์๋ง์ ์๋น์ค์ ์กด์ฌ๋ก ์ธํด ๋ฌ๋ ์ปค๋ธ๊ฐ ๋์ผ๋ฉฐ ๋ณต์กํ ์๊ธ ๊ตฌ์กฐ๋ก ๊ด๋ฆฌ์ ์ด๋ ค์์ด ์์ ์ ์๋ค.
Firebase์ ์ฃผ์ ์ ํ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค - Firestore, Realtime DB
- ์๋ฒ๋ฆฌ์ค - Cloud Functions
- ์ ์ฅ์ - Cloud Storage
- ์ธ์ฆ - Authentication
- ์๊ฒฉ ์ค์ - Remote Config
- ํธ์ ์๋ฆผ - Cloud Messaging
- ํฌ๋์ ๋ถ์ - Crashlytics
- ์๋น์ค ๋ถ์ - Google Analytics
Firebase ์ค์ ๊ณผ Firestore ์์ฑ
- ํ๋ก์ ํธ ์์ฑ > ํ๋ก์ ํธ ์ค์ > SDK ๋ฐ๊ธ (์ ์ถ๋๊ฑฐ๋ ์์ด๋ฒ๋ฆฌ๋ฉด ์๋จ!!)
- Firestore ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ฑ
- ์์น (us), ํ ์คํธ ๋ชจ๋ ์ฒดํฌ ํ ์์ฑ
- Firebase ํ๋ก์ ํธ์ ์ค์ ํ๊ธฐ (firebase-admin ์ค์น)
npm install firebase-admin
- Firestore.js
import { initializeApp, cert } from 'firebase-admin/app';
initializeApp({
credential: cert('security/test-cloud-3dd82-firebase-adminsdk-zn4e0-a09b4732f0.json'),
});
๋ณด์ํค ํ์ผ์ ๋ถ๋ฌ์์ security ํด๋์ ์ ์ฅํ๋ค. ํด๋น ํด๋๋ ๋ ธ์ถ๋์ง ์๋๋ก gitignore ๋ฑ์ ํตํด git์ ์ฌ๋ผ๊ฐ์ง ์๋๋ก ์ฃผ์ํด์ผ ํ๋ค.
initializeApp์ผ๋ก firebase๋ฅผ ๋ถ๋ฌ์ฌ ์ ์๋ค.
import { initializeApp, cert } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
initializeApp({
credential: cert('security/test-cloud-3dd82-firebase-adminsdk-zn4e0-a09b4732f0.json'),
});
export const db = getFirestore();
firestore๋ฅผ ๋ถ๋ฌ์ค๊ธฐ ์ํด getFirestore() ํจ์๋ฅผ ์ฌ์ฉํ๋ค.
- firestore์ ๋ฐ์ดํฐ ์ ์ฅํ๊ธฐ ์์
const db = getFirestore();
db.collection('test')
.doc('id')
.set({
data: {
x: 1,
y: 2,
},
});
add๋ก ์ถ๊ฐํ ๊ฒฝ์ฐ, firebase์์ ์ง์ ์๋ณ์๋ฅผ ์์ฑํด์ ์ ์ฅํ๋ค.
db.collection('articles').add(article);
Firebase CRUD
- ์กฐํ (get ๋ฉ์๋)
router.get('', async (req, res) => {
const articlesRef = await db.collection('articles').get();
res.status(200).json({
_embedded: {
articles: articlesRef.docs.map((article) => makeHalResource(article.data(), 'articles')),
},
});
});
- ๋จ๊ฑด ์กฐํ
router.get('/:articleId', async (req, res) => {
const { articleId } = req.params;
const articleRef = await db.collection('articles').doc(articleId).get();
if (!articleRef.exists) {
return res.status(404).json({
_links: {
articles: {
href: req.baseUrl,
},
},
message: '์กฐํํ๋ ค๋ ๊ฒ์๊ธ์ด ์กด์ฌํ์ง ์์ต๋๋ค.',
error: 'Not Found',
});
}
res.status(200).json({
_embedded: {
article: makeHalResource(articleRef.data(), 'articles'),
},
});
});
- ์์ (get, set ๋ฉ์๋)
router.put('/:articleId', async (req, res) => {
const { articleId } = req.params;
const articleRef = await db.collection('articles').doc(articleId);
const articleDoc = await articleRef.get();
if (!articleDoc.exists) {
return res.sendStatus(404);
}
const { error, value } = articleUpdateSchema.validate(req.body);
if (error) {
return res.status(400).json({
error: error.name,
message: error.details[0].message,
});
}
const article = {
...value,
id: articleId,
};
articleRef.set(value, { merge: true });
res.status(200).json({
_embedded: {
article: makeHalResource(article, 'articles'),
},
});
});
- ์ญ์ (delete ๋ฉ์๋)
router.delete('/:articleId', async (req, res) => {
const { articleId } = req.params;
const articleRef = db.collection('articles').doc(articleId);
const articleDoc = await articleRef.get();
if (!articleDoc.exists) {
return res.sendStatus(404);
}
await articleRef.delete();
res.sendStatus(204);
});
- ํค ๊ฐ์ด ์๋ ์กฐ๊ฑด์ผ๋ก ์กฐํํ๋ ค๋ ๊ฒฝ์ฐ (where ๋ฉ์๋)
const userRef = db.collection('users').where("username", '==', username)
const userQuery = await userRef.get()
if (!userQuery.empty) {
return res.sendStatus(404);
}
// ์ค์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
const user = userQuery.docs[0].data();
๋ง๋ฌด๋ฆฌ
Firebase์ Firestore ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ค์ ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ์ค์ต์ ํด๋ดค๋๋ฐ ์๊ฐ๋ณด๋ค ๊ฐ๋จํด์ ์ฌ์ด๋ ํ๋ก์ ํธ์ ํ์ฉํ๊ธฐ ์ข์๋ณด์๋ค.
