๊ฐœ๋ฐœ ๊ณต๋ถ€/๋ฐ๋ธŒ์ฝ”์Šค TIL

[ํด๋ผ์šฐ๋”ฉ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—”์ง€๋‹ˆ์–ด๋ง TIL] 240415 - ํด๋ผ์šฐ๋“œ ์ปดํ“จํŒ… & Firebase

๊ฐ€์šค์ด 2024. 4. 15. 20:04

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 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์‹ค์ œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ์‹ค์Šต์„ ํ•ด๋ดค๋Š”๋ฐ ์ƒ๊ฐ๋ณด๋‹ค ๊ฐ„๋‹จํ•ด์„œ ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ์— ํ™œ์šฉํ•˜๊ธฐ ์ข‹์•„๋ณด์˜€๋‹ค.