N

Nokfa Docs

Current: framework-next.js

ไม่มีชื่อบทความ

⚙️ ออกแบบ “Firestore Service Layer” – แยก Logic อ่าน/เขียนให้ทดสอบง่าย

โฟลเดอร์ที่แนะนำ

สร้างไฟล์ใน /services/firestore/:

services/
└── firestore/
    ├── addMessage.js
    ├── getMessages.js
    └── updateMessage.js

🔹 ตัวอย่าง addMessage.js

import { collection, addDoc } from 'firebase/firestore';
import { db } from '@/lib/firebaseClient';

export async function addMessage(data) {
  try {
    const docRef = await addDoc(collection(db, 'messages'), data);
    return { id: docRef.id };
  } catch (err) {
    console.error('[addMessage] ❌', err);
    throw new Error('ไม่สามารถเพิ่มข้อความได้');
  }
}

🔹 ตัวอย่าง getMessages.js

import { collection, getDocs } from 'firebase/firestore';
import { db } from '@/lib/firebaseClient';

export async function getMessages() {
  try {
    const snap = await getDocs(collection(db, 'messages'));
    return snap.docs.map(doc => ({ id: doc.id, ...doc.data() }));
  } catch (err) {
    console.error('[getMessages] ❌', err);
    return [];
  }
}

🔹 ตัวอย่าง updateMessage.js

import { doc, updateDoc } from 'firebase/firestore';
import { db } from '@/lib/firebaseClient';

export async function updateMessage(id, newData) {
  try {
    const docRef = doc(db, 'messages', id);
    await updateDoc(docRef, newData);
    return true;
  } catch (err) {
    console.error('[updateMessage] ❌', err);
    return false;
  }
}

✅ จุดเด่นของการแยก Service Layer

  • Separation of Concerns: หน้า UI ไม่ต้องมี logic Firebase โดยตรง
  • Reusability: เรียกซ้ำได้จากหลาย component หรือ API
  • Testability: นำไปเขียน Unit Test ได้ง่ายขึ้น

🧪 ตัวอย่างการทดสอบด้วย Vitest (ข้ามได้หากยังไม่ใช้)

// tests/services/firestore/addMessage.test.js
import { describe, it, expect, vi } from 'vitest';
import { addMessage } from '@/services/firestore/addMessage';

vi.mock('@/lib/firebaseClient', () => ({
  db: {},
}));

vi.mock('firebase/firestore', () => ({
  collection: vi.fn(),
  addDoc: vi.fn(() => Promise.resolve({ id: 'mock-id' })),
}));

describe('addMessage()', () => {
  it('should return doc id', async () => {
    const result = await addMessage({ text: 'Hello' });
    expect(result.id).toBe('mock-id');
  });
});

สามารถใช้แนวทางนี้กับ Collection อื่น ๆ ได้เช่นกัน เช่น users, comments, logs ฯลฯ หากต้องการเวอร์ชัน TypeScript ก็สามารถใช้ generics T เพิ่มเข้าไปใน type ของ data ที่รับเข้า/ส่งออก