GoogleRun Wrapper: ตัวช่วยเรียกใช้ Google Apps Script ให้ใช้งานง่ายขึ้น

 


ทำไมต้องมี Wrapper?

      เวลาพัฒนา Web App ด้วย Google Apps Script (GAS) เรามักต้องเขียนโค้ดฝั่ง Client (HTML/JS) ให้เรียกฟังก์ชันฝั่ง Server (Code.gs) ผ่าน google.script.run

โดยปกติ การเขียน google.script.run ตรง ๆ จะมีลักษณะเช่นนี้:

google.script.run .withSuccessHandler(res => { console.log("Success:", res); }) .withFailureHandler(err => { console.error("Error:", err); }) .myServerFunction("some data");


แม้จะใช้งานได้ แต่ปัญหาคือ

  • โค้ดซ้ำ ๆ เยอะ (ต้องเขียน Success/Failure handler ทุกครั้ง)
  • ไม่รองรับ async/await โดยตรง (ทำให้โค้ดอ่านยากเมื่อมีหลายการเรียก)
  • ทำให้การจัดการ Error ไม่เป็นระบบ

👉 ตรงนี้เองที่ GoogleRun Wrapper ถูกสร้างขึ้นมา เพื่อเปลี่ยน google.script.run ให้อยู่ในรูปที่ใช้ง่ายขึ้น เหมือนเรียกใช้ API ปกติ


ตัวอย่าง GoogleRun Wrapper

function googleRun(funcName, ...args) { return new Promise((resolve, reject) => { google.script.run .withSuccessHandler(resolve) .withFailureHandler(reject)[funcName](...args); }); }


การใช้งาน:

async function loadData() { try { const result = await googleRun("getDataFromSheet", "Sheet1"); console.log(result); } catch (err) { console.error("Error:", err); } }

✅ ข้อดี (Pros)

1. ใช้ง่ายขึ้น
      เรียกเหมือนฟังก์ชันปกติ await googleRun("func", arg1, arg2)
2. รองรับ async/await
      ทำให้โค้ดอ่านง่าย ไม่ซับซ้อน
3. จัดการ Error ได้เป็นระบบ
      ไม่ต้องเขียน withFailureHandler ทุกครั้ง
4. ลดการเขียนโค้ดซ้ำ
      Handler ส่วนกลางอยู่ใน Wrapper เดียว
5. ใช้ซ้ำได้หลายโปรเจกต์
      สามารถ copy ไปใช้ใน web app อื่น ๆ ได้เลย

❌ ข้อเสีย (Cons)

1. ต้องเขียน Wrapper เพิ่มเอง
      ผู้เริ่มต้นอาจไม่เข้าใจว่าเกิดอะไรขึ้นเบื้องหลัง
2. Debug ยากขึ้นเล็กน้อย
      ถ้า Wrapper มีบั๊ก อาจไม่รู้ว่าปัญหาอยู่ที่ฝั่งไหน (Client/Server)
3. ไม่เหมาะกับโค้ดเล็กมาก ๆ
      ถ้าโปรเจกต์มีแค่การเรียก google.script.run 1–2 ครั้ง อาจไม่จำเป็น

🔹 ประโยชน์ (Use Cases)

1. Web App ที่ต้องติดต่อกับ Google Sheets/Drive หลายครั้ง
      เช่น ระบบจองห้อง, ระบบเช็กชื่อ, ระบบบันทึกข้อมูล
2. โปรเจกต์ที่ต้องการโค้ดอ่านง่าย
      ใช้ async/await แทนการเขียน callback ซ้อนกัน
3. โปรเจกต์ที่ทีมพัฒนาหลายคน
      Wrapper ทำให้ทุกคนใช้โค้ดรูปแบบเดียวกัน ลดความผิดพลาด

สรุป

GoogleRun Wrapper เป็นวิธีทำให้ google.script.run ใช้งานสะดวกขึ้นมาก โดยเปลี่ยนการทำงานแบบ Callback ให้เป็น Promise/async-await

  • ถ้าโปรเจกต์เล็ก: เขียนตรง ๆ ก็พอ
  • ถ้าโปรเจกต์ใหญ่: ใช้ Wrapper จะช่วยให้อ่านง่าย ดูแลรักษาง่าย และลดความซ้ำซ้อน

ตัวอย่างการใช้งาน

Code.gs

     
/**
 * ชี้ไปที่ Spreadsheet
 */
const SPREADSHEET_ID = "YOUR_SPREADSHEET_ID";
const SHEET_NAME = "Users";

/**
 * โหลดไฟล์ HTML (Frontend)
 */
function doGet() {
  return HtmlService.createTemplateFromFile("index").evaluate()
    .setTitle("Async/Await Demo")
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

/**
 * โหลดข้อมูลจาก Google Sheet
 */
function getUsers() {
  const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheet = ss.getSheetByName(SHEET_NAME);
  const values = sheet.getDataRange().getValues();

  // แปลงเป็น JSON
  const headers = values.shift();
  return values.map(row => {
    let obj = {};
    headers.forEach((h, i) => obj[h] = row[i]);
    return obj;
  });
}

/**
 * เพิ่มผู้ใช้ใหม่
 */
function addUser(user) {
  const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheet = ss.getSheetByName(SHEET_NAME);
  sheet.appendRow([user.name, user.email, user.role]);
  return { success: true, message: "เพิ่มผู้ใช้สำเร็จ ✅" };
}


    

index.html

     
<!DOCTYPE html>
<html lang="th">
<head>
  <meta charset="UTF-8">
  <title>Async/Await Demo</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="p-4">
  <div class="container">
    <h2 class="mb-4">📋 รายชื่อผู้ใช้งาน</h2>

    <!-- ตารางผู้ใช้ -->
    <table class="table table-bordered">
      <thead>
        <tr>
          <th>ชื่อ</th>
          <th>อีเมล</th>
          <th>บทบาท</th>
        </tr>
      </thead>
      <tbody id="userTable"></tbody>
    </table>

    <!-- ฟอร์มเพิ่มผู้ใช้ -->
    <h4 class="mt-4">➕ เพิ่มผู้ใช้ใหม่</h4>
    <form id="userForm">
      <div class="mb-3">
        <label class="form-label">ชื่อ</label>
        <input type="text" class="form-control" id="name" required>
      </div>
      <div class="mb-3">
        <label class="form-label">อีเมล</label>
        <input type="email" class="form-control" id="email" required>
      </div>
      <div class="mb-3">
        <label class="form-label">บทบาท</label>
        <select class="form-select" id="role" required>
          <option value="Admin">Admin</option>
          <option value="User">User</option>
        </select>
      </div>
      <button type="submit" class="btn btn-primary">บันทึก</button>
    </form>

    <div id="message" class="mt-3"></div>
  </div>

  <script>
    // ✅ async/await wrapper for google.script.run
    function runAsync(funcName, ...args) {
      return new Promise((resolve, reject) => {
        google.script.run
          .withSuccessHandler(resolve)
          .withFailureHandler(reject)[funcName](...args);
      });
    }

    // โหลดข้อมูลมาใส่ตาราง
    async function loadUsers() {
      try {
        const users = await runAsync("getUsers");
        const tbody = document.getElementById("userTable");
        tbody.innerHTML = "";
        users.forEach(u => {
          const tr = document.createElement("tr");
          tr.innerHTML = `<td>${u.name}</td><td>${u.email}</td><td>${u.role}</td>`;
          tbody.appendChild(tr);
        });
      } catch (err) {
        console.error("โหลดข้อมูลล้มเหลว", err);
      }
    }

    // จัดการ submit form
    document.getElementById("userForm").addEventListener("submit", async (e) => {
      e.preventDefault();
      const user = {
        name: document.getElementById("name").value,
        email: document.getElementById("email").value,
        role: document.getElementById("role").value
      };

      try {
        const res = await runAsync("addUser", user);
        document.getElementById("message").innerHTML =
          `<div class="alert alert-success">${res.message}</div>`;
        e.target.reset();
        loadUsers(); // reload table
      } catch (err) {
        document.getElementById("message").innerHTML =
          `<div class="alert alert-danger">❌ เกิดข้อผิดพลาด: ${err}</div>`;
      }
    });

    // เริ่มโหลดเมื่อเปิดหน้า
    loadUsers();
  </script>
</body>
</html>


    


หากเห็นว่ามีประโยชน์โปรดร่วมสนับสนุน เพื่อเป็นกำลังใจในการพัฒนาต่อไป



แสดงความคิดเห็น (0)
ใหม่กว่า เก่ากว่า