ป้ายกำกับ: Api Design

ฟอร์มเดียวหลายหน้าที่ พรีวิวก็ได้ บันทึกก็ดีฟอร์มเดียวหลายหน้าที่ พรีวิวก็ได้ บันทึกก็ดี

ในโลกของการพัฒนาแอปพลิเคชันที่ซับซ้อน การจัดการข้อมูลที่มาจากฟอร์มเดียวแต่มีวัตถุประสงค์หลายอย่าง (เช่น การดูตัวอย่างข้อมูลก่อนบันทึก หรือการบันทึกข้อมูลจริง) เป็นความท้าทายหลักทางสถาปัตยกรรม การพึ่งพา Logic ที่ฝั่ง Client (JavaScript) เพียงอย่างเดียวอาจทำให้เกิดช่องโหว่ด้านความปลอดภัยและความไม่สอดคล้องของข้อมูล

ในฐานะ System Specialist เราจึงต้องย้ายการควบคุมการทำงานทั้งหมดมาที่ Backend ซึ่งก็คือ PostgreSQL นี่คือแนวทางในการออกแบบระบบที่ใช้ฟังก์ชันเดียวในการจัดการทั้งการ ‘Preview’ (ตรวจสอบ) และ ‘Save’ (บันทึก) เพื่อรับประกันความสมบูรณ์ของข้อมูล (Data Integrity) ตั้งแต่ต้นทาง

💡 หลักการออกแบบ: การใช้ Parameter Mode ใน PostgreSQL

แทนที่จะสร้าง API หรือฟังก์ชันแยกกันสำหรับ ‘Preview’ และ ‘Save’ เราสามารถออกแบบฟังก์ชัน PostgreSQL เพียงตัวเดียวที่รับพารามิเตอร์สถานะ (Mode) เข้ามาด้วย ฟังก์ชันนี้จะทำหน้าที่เป็น Single Source of Truth โดยจะตรวจสอบค่าของ Mode ก่อนตัดสินใจว่าจะดำเนินการแค่การตรวจสอบความถูกต้อง (Validation/Select) หรือดำเนินการบันทึกข้อมูลจริง (Insert/Update)

⚙️ ตัวอย่างการใช้งาน PL/pgSQL Function

เราจะสร้างฟังก์ชันที่รับค่าข้อมูล JSON (จำลองข้อมูลจากฟอร์ม) และค่า Mode (‘preview’ หรือ ‘save’) เข้ามา:

SQL

-- 1. สร้างตารางสำหรับเก็บข้อมูล (สมมติ) --
CREATE TABLE user_submissions (
    id SERIAL PRIMARY KEY,
    data_key TEXT NOT NULL,
    data_value TEXT NOT NULL,
    submission_mode TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 2. สร้างฟังก์ชันหลักที่จัดการหลายโหมด --
CREATE OR REPLACE FUNCTION process_form_submission(
    p_data JSONB, 
    p_mode TEXT
) RETURNS JSONB AS $$
DECLARE
    v_status TEXT := '';
BEGIN
    IF p_mode = 'preview' THEN
        -- โหมด Preview: ตรวจสอบความถูกต้องของข้อมูลเท่านั้น (SELECT/VALIDATE)
        -- เราสามารถตรวจสอบว่าข้อมูลที่ส่งมามีรูปแบบที่ถูกต้องหรือไม่ โดยไม่บันทึก
        IF p_data->>'data_key' IS NULL OR p_data->>'data_value' IS NULL THEN
            RETURN jsonb_build_object('success', FALSE, 'message', 'Preview failed: Missing required data.');
        END IF;
        
        -- หากผ่านการตรวจสอบ จะส่งข้อความยืนยันว่าข้อมูลพร้อมสำหรับการบันทึก
        RETURN jsonb_build_object('success', TRUE, 'message', 'Preview successful. Data is valid for saving.');

    ELSIF p_mode = 'save' THEN
        -- โหมด Save: ดำเนินการบันทึกข้อมูลจริง (INSERT/UPDATE)
        INSERT INTO user_submissions (data_key, data_value, submission_mode) 
        VALUES (p_data->>'data_key', p_data->>'data_value', p_mode);
        
        RETURN jsonb_build_object('success', TRUE, 'message', 'Data saved successfully.');

    ELSE
        -- กรณีโหมดไม่ถูกต้อง
        RETURN jsonb_build_object('success', FALSE, 'message', 'Invalid submission mode specified.');
    END IF;
END;
$$ LANGUAGE plpgsql;

-- 3. ตัวอย่างการเรียกใช้ (Scenario 1: Preview)
SELECT process_form_submission('{"data_key": "apple", "data_value": "1,2,3"}', 'preview');

-- 4. ตัวอย่างการเรียกใช้ (Scenario 2: Save)
SELECT process_form_submission('{"data_key": "banana", "data_value": "4,5,6"}', 'save');

✅ ประโยชน์ทางสถาปัตยกรรม

การใช้ฟังก์ชันแบบนี้ทำให้เกิดประโยชน์สูงสุดในหลายมิติ:

  • Single Entry Point: ทุกการส่งข้อมูลจะถูกจัดการที่ฟังก์ชันเดียว ทำให้ง่ายต่อการบำรุงรักษาและการตรวจสอบ (Auditability)
  • Data Integrity: โหมด ‘preview’ ช่วยให้เราสามารถรัน Logic การตรวจสอบความถูกต้อง (Validation Logic) ที่ซับซ้อนได้ก่อนที่ข้อมูลจะถูกเขียนลงฐานข้อมูลจริง
  • Security: ลดความเสี่ยงจากการที่ Client-side Logic ถูกข้ามไปได้ เพราะการตัดสินใจทั้งหมดเกิดขึ้นที่ระดับ Database (Server-side)

🚀 บทสรุป

การจัดการฟอร์มที่มีหลายสถานะใน PostgreSQL ไม่ได้หมายถึงการเขียนโค้ดหลายส่วน แต่หมายถึงการออกแบบ Logic ที่ชาญฉลาดภายในฟังก์ชันเดียว การใช้พารามิเตอร์ ‘Mode’ เป็นกลไกที่ทรงพลังในการแยกการทำงานระหว่างการตรวจสอบ (Preview) และการบันทึก (Save) อย่างชัดเจน ทำให้ระบบของคุณมีความเสถียร ปลอดภัย และเป็นไปตามหลักการของ Senior Architect ในการออกแบบระบบฐานข้อมูลที่แข็งแกร่ง