คุณกำลังสร้างแอปที่ต้องมีระบบล็อกอิน, ซิงค์ข้อมูลแบบเรียลไทม์, และจัดการไฟล์ หากคุณไม่อยากเสียเวลาหลายสัปดาห์กับการตั้งเซิร์ฟเวอร์และโครงสร้างพื้นฐาน Firebase คือทางเลือกที่ตอบโจทย์
Firebase เป็นเบื้องหลังของแอปมากกว่า 1.5 ล้านแอป เช่น The New York Times, Duolingo และ Alibaba เพราะช่วยลดภาระฝั่ง backend ทำให้คุณโฟกัสที่ feature ไม่ต้องดูแลเซิร์ฟเวอร์เอง อย่างไรก็ตาม Firebase API มีจุดที่ต้องระวัง เช่น authentication ที่อาจสับสนสำหรับมือใหม่, database rules ที่ผิดพลาดบ่อย, หรือ Cloud Functions ที่ต้องเข้าใจเรื่อง trigger ให้ดี
ผมเคยนำ Firebase ไปใช้กับระบบที่มีผู้ใช้งานหลักล้าน เจอปัญหาทุกแบบ ตั้งแต่เปิด key service account ผิดที่, query ไม่ optimize, ไปจนถึง function ล่ม คู่มือนี้จะสรุปวิธีปฏิบัติจริง พร้อมโค้ดตัวอย่าง และข้อผิดพลาดที่ควรหลีกเลี่ยง
คุณจะได้ลงมือกับ authentication, database, Cloud Functions, และ storage พร้อมตัวอย่างโค้ดใช้งานจริง
💡การทดสอบ Firebase API จะง่ายขึ้นด้วยเครื่องมือไคลเอ็นต์ API ที่เหมาะสม Apidog ช่วยให้คุณจัดระเบียบเอนด์พอยต์, ทดสอบ authentication flow และแชร์ collection กับทีมได้ ดูวิธีผสานเข้ากับ workflow ด้านล่าง
Firebase API คืออะไร และทำไมถึงสำคัญ?
Firebase ไม่ใช่ API ตัวเดียว แต่เป็นชุดบริการ backend ที่เข้าถึงผ่าน SDK และ REST endpoint ได้
บริการหลักของ Firebase
| บริการ | วัตถุประสงค์ | ประเภท API |
|---|---|---|
| การยืนยันตัวตน | การเข้าสู่ระบบและระบุตัวตนของผู้ใช้ | SDK + REST |
| ฐานข้อมูล Firestore | ฐานข้อมูลเอกสาร NoSQL | SDK + REST |
| ฐานข้อมูล Realtime | การซิงค์ JSON แบบเรียลไทม์ | SDK + REST |
| Cloud Storage | การจัดเก็บไฟล์และ CDN | SDK + REST |
| Cloud Functions | การประมวลผลแบบไร้เซิร์ฟเวอร์ | Deployment CLI |
| Hosting | การโฮสต์เว็บแบบคงที่ | Deployment CLI |
| Cloud Messaging | การแจ้งเตือนแบบพุช (Push notifications) | HTTP v1 API |
เมื่อใดที่ Firebase เหมาะสม
Firebase เหมาะกับ use case แบบนี้:
- ต้องการซิงค์ข้อมูล real-time (เช่น แชท, live update)
- ต้องการ serverless ไม่ต้องดูแล infra
- สร้าง mobile/web app (SDK รองรับ platform หลายแบบ)
- ต้องการ offline (SDK มี cache ในตัว)
- ต้องการ auth ในตัว (Google, Apple, email, phone)
แต่ไม่ควรใช้หาก:
- ต้องการ query แบบ relational ที่ซับซ้อน
- มีข้อบังคับ data residency (region จำกัด)
- ต้องการ SQL เต็มรูปแบบ
- ต้องการควบคุมต้นทุนสูงสุด (host เองอาจถูกกว่า)
สถาปัตยกรรม Firebase API
Firebase ใช้ client SDK จัดการ HTTP/WebSocket และ auth token ให้เบื้องหลัง:
┌─────────────────────────────────────────────────────────┐
│ Your Application │
├─────────────────────────────────────────────────────────┤
│ Firebase SDK (Client) │
│ - Auto-handles auth tokens │
│ - Manages offline cache │
│ - Real-time listeners │
└─────────────────────────────────────────────────────────┘
│
│ HTTPS + WebSocket
▼
┌─────────────────────────────────────────────────────────┐
│ Firebase Backend │
├──────────────┬──────────────┬──────────────┬────────────┤
│ Auth │ Firestore │ Storage │ Functions │
│ Service │ Database │ Service │ Runtime │
└──────────────┴──────────────┴──────────────┴────────────┘
Client SDKs จะจัดการ layer HTTP ให้โดยอัตโนมัติ ทุก action คือ REST API + JWT auth
การยืนยันตัวตนด้วย Firebase: ขั้นตอนครบจบ
เริ่มต้น integrate Firebase ให้ถูกจุดด้วย auth ถ้าตั้งค่าผิด ทุกอย่างจะพังหมด
ขั้นตอนที่ 1: สร้างโปรเจกต์ Firebase
- ไปที่ Firebase Console
- คลิก “Add project” ใส่ชื่อโปรเจกต์ (ห้ามมีเว้นวรรค)
- เปิดใช้ Google Analytics (ถ้าต้องการ)
- คลิก “Create project” แล้วรอจนขึ้น dashboard
(ดูรูปในบทความเดิม)
ขั้นตอนที่ 2: ลงทะเบียนแอปของคุณ
Web:
const firebaseConfig = {
apiKey: "AIzaSyDxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "your-app.firebaseapp.com",
projectId: "your-app",
storageBucket: "your-app.appspot.com",
messagingSenderId: "123456789012",
appId: "1:123456789012:web:abc123def456"
};
import { initializeApp } from 'firebase/app';
const app = initializeApp(firebaseConfig);
iOS: ดาวน์โหลด GoogleService-Info.plist แล้วใส่ใน Xcode target
Android: ดาวน์โหลด google-services.json ใส่โฟลเดอร์ app/ และเพิ่มใน build.gradle:
// Project-level build.gradle
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.4.0'
}
}
// App-level build.gradle
plugins {
id 'com.google.gms.google-services'
}
ขั้นตอนที่ 3: เปิดใช้งานวิธีการยืนยันตัวตน
ใน Firebase Console > Authentication > Sign-in method:
- เปิด Email/Password
- เพิ่ม Google (ต้องกรอก SHA-1 certificate สำหรับ Android)
- Apple สำหรับ iOS (ถ้า app รองรับ social login)
- Phone (ถ้าใช้ SMS จะต้องเปิด billing)
ขั้นตอนที่ 4: เขียนโค้ดยืนยันตัวตน
สมัครสมาชิกด้วยอีเมล/รหัสผ่าน:
import {
createUserWithEmailAndPassword,
getAuth,
updateProfile
} from 'firebase/auth';
const auth = getAuth(app);
async function signUp(email, password, displayName) {
try {
const userCredential = await createUserWithEmailAndPassword(
auth,
email,
password
);
await updateProfile(userCredential.user, { displayName });
return userCredential.user;
} catch (error) {
switch (error.code) {
case 'auth/email-already-in-use':
throw new Error('อีเมลนี้ลงทะเบียนแล้ว');
case 'auth/weak-password':
throw new Error('รหัสผ่านต้องอย่างน้อย 6 ตัว');
case 'auth/invalid-email':
throw new Error('อีเมลไม่ถูกต้อง');
default:
throw new Error('สมัครสมาชิกล้มเหลว: ' + error.message);
}
}
}
เข้าสู่ระบบด้วยอีเมล/รหัสผ่าน:
import {
signInWithEmailAndPassword,
signOut
} from 'firebase/auth';
async function signIn(email, password) {
try {
const userCredential = await signInWithEmailAndPassword(
auth,
email,
password
);
const user = userCredential.user;
const idToken = await user.getIdToken();
return user;
} catch (error) {
switch (error.code) {
case 'auth/user-not-found':
throw new Error('ไม่พบอีเมลนี้');
case 'auth/wrong-password':
throw new Error('รหัสผ่านไม่ถูกต้อง');
case 'auth/too-many-requests':
throw new Error('ลองใหม่ภายหลัง');
default:
throw new Error('เข้าสู่ระบบล้มเหลว');
}
}
}
async function logOut() {
await signOut(auth);
}
เข้าสู่ระบบด้วย Google (Web):
import {
GoogleAuthProvider,
signInWithPopup
} from 'firebase/auth';
async function signInWithGoogle() {
const provider = new GoogleAuthProvider();
provider.addScope('email');
provider.addScope('profile');
try {
const result = await signInWithPopup(auth, provider);
return result.user;
} catch (error) {
if (error.code === 'auth/popup-closed-by-user') {
throw new Error('ยกเลิกการเข้าสู่ระบบ');
}
throw new Error('Google sign-in failed');
}
}
ขั้นตอนที่ 5: ปกป้อง routes ด้วย auth status
import { onAuthStateChanged } from 'firebase/auth';
onAuthStateChanged(auth, (user) => {
if (user) {
window.location.href = '/dashboard';
} else {
window.location.href = '/login';
}
});
ข้อผิดพลาด auth ที่พบบ่อย
1. ลืม handle token refresh
SDK จะ refresh token ให้ แต่ถ้าคุณ cache token ฝั่ง server ต้อง handle expire ทุก 1 ชั่วโมง
2. เปิดเผย service account ใน client
ห้ามใช้ key ฝั่ง client เด็ดขาด ใช้เฉพาะบน server เท่านั้น
3. ไม่บังคับ verify email
import { sendEmailVerification } from 'firebase/auth';
async function sendVerificationEmail(user) {
await sendEmailVerification(user);
}
if (!auth.currentUser.emailVerified) {
// Block access
}
ฐานข้อมูล Firestore: CRUD และ Query
Firestore คือ NoSQL database ที่ scale อัตโนมัติและ query ได้เร็ว
โครงสร้างข้อมูล
your-project (root)
└── users (collection)
├── userId123 (document)
│ ├── name: "John"
│ ├── email: "john@example.com"
│ └── posts (subcollection)
│ ├── postId1 (document)
│ └── postId2 (document)
└── userId456 (document)
เริ่มใช้งาน Firestore
import { getFirestore } from 'firebase/firestore';
const db = getFirestore(app);
สร้างเอกสาร
import { collection, addDoc, setDoc, doc } from 'firebase/firestore';
async function createUser(userData) {
const docRef = await addDoc(collection(db, 'users'), userData);
return docRef.id;
}
async function createUserWithId(userId, userData) {
await setDoc(doc(db, 'users', userId), userData);
}
อ่านเอกสาร
import { getDoc, getDocs, query, where, orderBy, limit } from 'firebase/firestore';
async function getUser(userId) {
const docRef = doc(db, 'users', userId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) return docSnap.data();
throw new Error('User not found');
}
async function getUsersByRole(role) {
const q = query(
collection(db, 'users'),
where('role', '==', role),
orderBy('createdAt', 'desc'),
limit(10)
);
const querySnapshot = await getDocs(q);
return querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
}
อัปเดตเอกสาร
import { updateDoc, increment, arrayUnion, arrayRemove } from 'firebase/firestore';
async function updateUser(userId, updates) {
const userRef = doc(db, 'users', userId);
await updateDoc(userRef, updates);
}
// ตัวอย่าง
await updateUser('userId123', {
loginCount: increment(1),
tags: arrayUnion('premium', 'beta-tester'),
lastLogin: new Date()
});
ลบเอกสาร
import { deleteDoc } from 'firebase/firestore';
async function deleteUser(userId) {
await deleteDoc(doc(db, 'users', userId));
}
Real-Time Listener
import { onSnapshot } from 'firebase/firestore';
const unsubscribe = onSnapshot(
doc(db, 'users', userId),
(doc) => {
console.log('User updated:', doc.data());
}
);
const q = query(collection(db, 'posts'), where('published', '==', true));
const unsubscribeQuery = onSnapshot(q, (snapshot) => {
const posts = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
console.log('Published posts:', posts);
});
Firestore Security Rules
ตั้งกฎใน Firebase Console > Firestore > Rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isAuthenticated() {
return request.auth != null;
}
function isOwner(userId) {
return request.auth.uid == userId;
}
match /users/{userId} {
allow read: if isAuthenticated();
allow create: if isAuthenticated() && isOwner(userId);
allow update, delete: if isOwner(userId);
}
match /posts/{postId} {
allow read: if true;
allow create: if isAuthenticated();
allow update, delete: if resource.data.authorId == request.auth.uid;
}
}
}
Firestore Query ข้อจำกัด
- ไม่มี OR โดยตรง (ใช้ in array หรือ query หลายครั้ง)
- ไม่มี wildcard search (ใช้ Algolia/Meilisearch แทน)
- Query ซับซ้อนต้องสร้าง composite index
- จำกัด 30 disjunctions ใน in query
ตัวอย่าง workaround OR query:
const activeQuery = query(collection(db, 'tasks'), where('status', '==', 'active'));
const pendingQuery = query(collection(db, 'tasks'), where('status', '==', 'pending'));
const [activeSnap, pendingSnap] = await Promise.all([
getDocs(activeQuery),
getDocs(pendingQuery)
]);
// รวมผลลัพธ์เอง
Cloud Functions: Backend แบบ Serverless
Cloud Functions คือ serverless backend สำหรับ trigger จาก DB, HTTP, หรือ schedule
การตั้งค่า
npm install -g firebase-tools
firebase login
firebase init functions
# เลือก JavaScript, ESLint yes, Express.js no
HTTP Functions (API Endpoint)
// functions/index.js
const { onRequest } = require('firebase-functions/v2/https');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.getPublicData = onRequest(async (req, res) => {
res.set('Access-Control-Allow-Origin', '*');
try {
const snapshot = await db.collection('public').get();
const data = snapshot.docs.map(doc => doc.data());
res.json({ success: true, data });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
exports.getUserProfile = onRequest(async (req, res) => {
res.set('Access-Control-Allow-Origin', '*');
const authHeader = req.headers.authorization || '';
const token = authHeader.split('Bearer ')[1];
if (!token) return res.status(401).json({ error: 'Unauthorized' });
try {
const decodedToken = await admin.auth().verifyIdToken(token);
const userId = decodedToken.uid;
const userDoc = await db.collection('users').doc(userId).get();
if (!userDoc.exists) return res.status(404).json({ error: 'User not found' });
res.json({ success: true, data: { id: userId, ...userDoc.data() } });
} catch (error) {
res.status(401).json({ error: 'Invalid token' });
}
});
Deploy:
firebase deploy --only functions:getUserProfile
เรียกจาก client:
async function getUserProfile(token) {
const response = await fetch(
'https://us-central1-your-app.cloudfunctions.net/getUserProfile',
{
headers: { 'Authorization': `Bearer ${token}` }
}
);
return await response.json();
}
Database Trigger
const { onDocumentWritten } = require('firebase-functions/v2/firestore');
exports.onUserUpdate = onDocumentWritten('users/{userId}', async (event) => {
const userId = event.params.userId;
const before = event.data?.before?.data();
const after = event.data?.after?.data();
if (before?.email !== after?.email) {
// ส่ง notification
}
});
Cron Job
const { onSchedule } = require('firebase-functions/v2/scheduler');
exports.dailyCleanup = onSchedule('every 24 hours', async (event) => {
// ลบ notification เก่า
});
Env Variable
firebase functions:config:set stripe.secret="sk_test_xxx" email.api_key="key_xxx"
const config = require('firebase-functions/config');
const stripe = require('stripe')(config.stripe.secret);
Cloud Storage: อัปโหลดและจัดการไฟล์
ตั้งค่า Storage Rules
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /users/{userId}/{allPaths=**} {
allow read: if true;
allow write, delete: if request.auth.uid == userId;
}
match /public/{allPaths=**} {
allow read: if true;
allow write: if false;
}
}
}
อัปโหลดไฟล์ (Client)
import { getStorage, ref, uploadBytesResumable, getDownloadURL } from 'firebase/storage';
const storage = getStorage(app);
async function uploadProfileImage(userId, file) {
const storageRef = ref(storage, `users/${userId}/profile/${file.name}`);
const uploadTask = uploadBytesResumable(storageRef, file);
return new Promise((resolve, reject) => {
uploadTask.on(
'state_changed',
(snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
},
(error) => reject(error),
async () => {
const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
resolve(downloadURL);
}
);
});
}
ดาวน์โหลดไฟล์
import { getDownloadURL } from 'firebase/storage';
async function getProfileImage(userId) {
const imageRef = ref(storage, `users/${userId}/profile/avatar.png`);
try {
return await getDownloadURL(imageRef);
} catch (error) {
if (error.code === 'storage/object-not-found') return null;
throw error;
}
}
ลบไฟล์
import { deleteObject } from 'firebase/storage';
async function deleteProfileImage(userId) {
const imageRef = ref(storage, `users/${userId}/profile/avatar.png`);
await deleteObject(imageRef);
}
การทดสอบ Firebase API ด้วย Apidog
Firebase มี REST API ครบทุกบริการ ทดสอบ request/response ได้ง่ายผ่าน Apidog
วิธีนำเข้า Firebase REST API
- เปิด Apidog
- สร้างโปรเจกต์ใหม่ ("Firebase API")
- นำเข้า OpenAPI spec หรือเพิ่ม endpoint เอง
ตัวอย่าง Firestore REST endpoint:
POST https://firestore.googleapis.com/v1/projects/{projectId}/databases/(default)/documents
Authorization: Bearer {oauth2_token}
Content-Type: application/json
{
"fields": {
"name": { "stringValue": "John" },
"email": { "stringValue": "john@example.com" },
"age": { "integerValue": 30 }
}
}
Auth endpoint:
POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key={api_key}
Content-Type: application/json
{
"email": "user@example.com",
"password": "secret123",
"returnSecureToken": true
}
ทดสอบ auth flow
- สร้าง request "Sign In" (POST)
- ใส่ email/password ใน body
- บันทึก token response เป็น environment variable
- ใช้
{{token}}ใน request ถัดไป
Debug Security Rules
ใช้ Firebase Emulator Suite:
firebase emulators:start
# ทดสอบ Firestore ที่ http://localhost:8080
Best Practices สำหรับ production
1. จัดการ error ให้ดี
async function firestoreWithRetry(operation, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await operation();
} catch (error) {
if (
error.code === 'unavailable' ||
error.code === 'deadline-exceeded'
) {
const delay = Math.pow(2, i) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
}
2. Optimize query ด้วย composite index
const q = query(
collection(db, 'posts'),
where('category', '==', 'tech'),
where('views', '>', 1000),
orderBy('views', 'desc')
);
// Firestore จะแจ้งให้สร้างดัชนีเองถ้าขาด
3. ใช้ batch operation
import { writeBatch } from 'firebase/firestore';
async function bulkUpdate(userIds, updates) {
const batch = writeBatch(db);
userIds.forEach(id => {
const ref = doc(db, 'users', id);
batch.update(ref, updates);
});
await batch.commit();
}
4. ติดตามค่าใช้จ่าย
ดูราคาคร่าวๆ ได้ในบทความ และตั้ง budget alert ใน Google Cloud Console
5. รักษาความปลอดภัย service accounts
ผิด:
admin.initializeApp({
credential: admin.credential.cert(require('./serviceAccountKey.json'))
});
ถูก:
const serviceAccount = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
6. รองรับ offline
import { enableMultiTabIndexedDbPersistence } from 'firebase/firestore';
enableMultiTabIndexedDbPersistence(db)
.catch((err) => {
if (err.code === 'failed-precondition') {
// มีหลาย tab
} else if (err.code === 'unimplemented') {
// browser ไม่รองรับ
}
});
ปัญหา Firebase API และวิธีแก้
1. PERMISSION_DENIED
- ตรวจสอบ security rules
- ตรวจว่า
request.auth.uidตรงกับ user ที่ต้องการ
2. Token หมดอายุ
const user = auth.currentUser;
if (user) {
await user.getIdToken(true); // Force refresh
}
3. Cold Start Function ช้า
exports.keepWarm = onSchedule('every 60 seconds', async () => {
await fetch('https://your-function.cloudfunctions.net/health');
});
4. Query ผลลัพธ์ว่าง
- ดัชนีขาด หรือลำดับฟิลด์ผิด
- ตรวจสอบ Firestore Console > Indexes
ตัวอย่างการใช้งานจริง
Fintech: อัปเดตธุรกรรม real-time
Cloud Functions + Firestore สามารถแจ้งเตือนธุรกรรมใหม่ไปยัง dashboard admin ได้ทันที ลด support ticket ได้มาก
E-commerce: ซิงค์สต็อกข้าม platform
Firestore listeners ช่วยให้ web/iOS/Android update stock ทันที รองรับ offline mode
SaaS: Multi-Tenant Auth
ใช้ Firebase Auth + custom claims + Cloud Functions เพื่อสร้าง B2B multi-tenant ที่รองรับ RBAC
สรุป
การใช้งาน Firebase API ครอบคลุม
- Auth: login อีเมล, Google, Apple, JWT
- Firestore: NoSQL, real-time, rules
- Cloud Functions: backend serverless trigger ได้ทั้ง HTTP/event
- Storage: อัปโหลดไฟล์ CDN
คุณได้ตัวอย่างโค้ดจริง, วิธีแก้ปัญหา, และ pattern สำหรับ production แล้ว
คำถามที่พบบ่อย
Firebase ใช้งานได้ฟรีหรือไม่?
ใช่ มี Spark Plan ฟรี รองรับ Storage 5GB, Firestore 50,000 read/วัน, Function 2 ล้าน call, Auth 10,000 user/เดือน
ฉันจะใช้ Firebase กับฐานข้อมูลเดิมได้ไหม?
ได้ ใช้ Firebase Extensions หรือ Cloud Functions เพื่อเชื่อมต่อกับ PostgreSQL/MySQL/MongoDB
จะย้ายจาก Firebase ไป platform อื่นอย่างไร?
ส่งออกข้อมูลด้วย Firestore export หรือ Firebase CLI ถ้าข้อมูลจำนวนมากใช้ Dataflow pipeline
Firebase รองรับ GraphQL ไหม?
ไม่โดยตรง ใช้ library ภายนอกหรือสร้าง layer GraphQL เองด้วย Cloud Functions
ใช้ Firebase แบบ on-premise ได้ไหม?
ไม่ได้ Firebase คือ Google Cloud service ล้วน ทางเลือก host เอง: Appwrite, Supabase, Nhost
อัปโหลดไฟล์ >100MB ทำอย่างไร?
ใช้ resumable upload (SDK ทำให้อัตโนมัติ) หรือ Google Cloud Storage + signed URL
ถ้าเกิน query limit Firestore?
จะ error FAILED_PRECONDITION ให้เพิ่มดัชนีหรือ restructure query Firestore จะมีลิงก์สร้าง index ให้อัตโนมัติ
Firebase compliant GDPR ไหม?
ใช่ มี region, data export/delete, และ Data Processing Amendment.
สำหรับใครที่ต้องการทดสอบ Firebase API และ workflow แบบมืออาชีพ ลอง Apidog ได้เลย
Top comments (0)