Kỹ thuật

Google Sheets API - Hướng Dẫn Tích Hợp Với Website & Ứng Dụng

Tuân HoangTuân Hoang
27 tháng 2, 2026
Cập nhật: 25 tháng 3, 2026
28 phút đọc
Google Sheets API - Hướng Dẫn Tích Hợp Với Website & Ứng Dụng

Google Sheets API là gì và tại sao bạn cần nó?

Bạn có một website bán hàng và muốn mỗi khi khách hàng điền form đặt hàng, dữ liệu tự động ghi vào Google Sheets để team vận hành xử lý? Hay bạn muốn xây dựng dashboard realtime đọc dữ liệu từ Google Sheets rồi hiển thị lên ứng dụng nội bộ? Hoặc đơn giản hơn - bạn muốn viết script tự động backup dữ liệu từ database vào Google Sheets hàng ngày?

Tất cả những nhu cầu này đều có thể giải quyết bằng Google Sheets API - một RESTful API cho phép bạn đọc, ghi, và quản lý Google Sheets từ bất kỳ ngôn ngữ lập trình nào. Phiên bản hiện tại là Google Sheets API v4, cung cấp khả năng truy cập toàn bộ chức năng của Google Sheets một cách có lập trình (programmatic).

Khác với Google Apps Script chỉ chạy trong môi trường Google, Google Sheets API cho phép bạn tích hợp Google Sheets vào bất kỳ ứng dụng nào - website Node.js, mobile app React Native, backend Python Django, hoặc thậm chí script cron job trên server. Đây chính là cầu nối giữa "thế giới Google Sheets" và "thế giới phần mềm bên ngoài".

Bài viết này sẽ giúp bạn:

  • Hiểu Google Sheets API v4 hoạt động như thế nào (REST endpoints, request/response)
  • Setup project trên Google Cloud Console từ đầu đến cuối
  • Phân biệt và cài đặt Service Account vs OAuth2 cho từng use case
  • Thực hiện CRUD operations (đọc, ghi, cập nhật, xóa) với JavaScript/Node.js
  • Xây dựng ví dụ thực tế: form website tự động ghi vào Sheets
  • Tham khảo code mẫu với Python (gspread)
  • Nắm rõ rate limits, quotas và cách xử lý khi vượt giới hạn
  • Áp dụng best practices bảo mật cho API key và service account

Phần 1: Google Sheets API v4 - Tổng quan kiến trúc

1.1 REST API v4 hoạt động như thế nào?

Google Sheets API v4 là một RESTful API, nghĩa là bạn tương tác với nó thông qua các HTTP request tiêu chuẩn (GET, POST, PUT, DELETE) tới các endpoint cố định. Mọi ngôn ngữ lập trình hỗ trợ HTTP đều có thể gọi API này.

Base URL của tất cả request là:

https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}

Trong đó spreadsheetId là ID của file Google Sheets - bạn có thể tìm thấy trong URL khi mở file trên trình duyệt:

https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms/edit
                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                         Phần này chính là spreadsheetId

Các resource chính của API bao gồm:

Resource Mô tả Endpoint
Spreadsheet Toàn bộ file spreadsheet GET /spreadsheets/{id}
Values Đọc/ghi dữ liệu cells GET/PUT /values/{range}
Sheets Quản lý individual sheets (tabs) POST /batchUpdate
Charts Tạo/sửa embedded charts POST /batchUpdate
DeveloperMetadata Metadata key-value tuỳ chỉnh POST /developerMetadata

1.2 Các use case phổ biến

Google Sheets API được sử dụng rộng rãi trong nhiều tình huống thực tế:

Form Website → Sheets

Khách hàng điền form trên website, dữ liệu tự động ghi vào Google Sheets. Team sale/vận hành xem và xử lý ngay trên Sheets quen thuộc.

Dashboard Realtime

Đọc dữ liệu từ Sheets hiển thị lên dashboard web/mobile. Team nhập liệu trên Sheets, dashboard tự cập nhật.

Data Sync / ETL

Đồng bộ dữ liệu giữa database/CRM/ERP với Google Sheets. Script chạy định kỳ export/import data.

Report Generation

Tự động tạo báo cáo hàng tuần/tháng lên Google Sheets, format đẹp, chia sẻ link cho team.

Phần 2: Setup Project trên Google Cloud Console

Trước khi gọi được API, bạn cần tạo project trên Google Cloud Console và enable Google Sheets API. Quy trình gồm 5 bước:

Bước 1: Tạo Google Cloud Project

  1. Truy cập console.cloud.google.com
  2. Click "Select a project""New Project"
  3. Đặt tên project (VD: "My Sheets Integration")
  4. Chọn Organization (nếu có) hoặc để "No organization"
  5. Click "Create" - đợi vài giây để project được tạo

Bước 2: Enable Google Sheets API

  1. Trong project vừa tạo, vào APIs & Services"Enable APIs and Services"
  2. Tìm kiếm "Google Sheets API"
  3. Click vào kết quả → Click "Enable"
  4. Nếu cần Google Drive API (tạo/xoá file), enable thêm "Google Drive API"

Bước 3: Tạo Credentials

Đây là bước quan trọng nhất - bạn cần chọn loại credentials phù hợp với use case:

Loại Credentials Use case Cách hoạt động
API Key Chỉ đọc data từ sheet public Đơn giản nhất, không cần OAuth
Service Account Server-to-server (backend, cron job, script) Dùng JSON key file, không cần user interaction
OAuth 2.0 Client ID User-facing app (user login, access their sheets) User phải đăng nhập Google, consent screen

Ghi nho quan trong:

  • 80% use case sử dụng Service Account - đây là lựa chọn phổ biến nhất cho tích hợp backend
  • Service Account có email riêng (dạng xxx@project.iam.gserviceaccount.com) - bạn cần share Google Sheets cho email này
  • OAuth 2.0 chỉ cần khi app cần truy cập sheets của người dùng cuối

Bước 4: Tạo Service Account (phổ biến nhất)

  1. Vào APIs & ServicesCredentials
  2. Click "Create Credentials""Service Account"
  3. Đặt tên (VD: "sheets-integration") → Click "Create and Continue"
  4. Ở "Grant this service account access to project" - chọn role "Editor" → Click "Continue"
  5. Click "Done"
  6. Click vào service account vừa tạo → Tab "Keys""Add Key""Create new key"
  7. Chọn JSON → Click "Create"
  8. File JSON sẽ được tải về - giữ bí mật file này!

Bước 5: Share Google Sheets cho Service Account

Sau khi tạo Service Account, bạn cần share file Google Sheets cho email của Service Account:

  1. Mở file Google Sheets trên trình duyệt
  2. Click nút "Share" (góc phải trên)
  3. Nhập email của Service Account (lấy từ file JSON vừa tải, trường "client_email")
  4. Chọn quyền: "Editor" (nếu cần ghi) hoặc "Viewer" (chỉ đọc)
  5. Bỏ tick "Notify people" → Click "Share"

Phần 3: Authentication chi tiết

3.1 Service Account Authentication (Server-to-Server)

Service Account là cách xác thực phổ biến nhất khi bạn muốn backend/server tự động tương tác với Google Sheets mà không cần user đăng nhập. Dưới đây là cách setup với Node.js:

Cài đặt dependencies:

npm install googleapis
# Hoặc chỉ cài riêng module google-auth-library + google-spreadsheet
npm install google-spreadsheet google-auth-library

Code xác thực với googleapis (official library):

const { google } = require('googleapis');

// Cach 1: Dung file JSON key (khuyen dung cho development)
const auth = new google.auth.GoogleAuth({
  keyFile: './service-account-key.json',
  scopes: ['https://www.googleapis.com/auth/spreadsheets'],
});

// Cach 2: Dung environment variables (khuyen dung cho production)
const auth2 = new google.auth.GoogleAuth({
  credentials: {
    client_email: process.env.GOOGLE_CLIENT_EMAIL,
    private_key: process.env.GOOGLE_PRIVATE_KEY.replace(/\n/g, '
'),
  },
  scopes: ['https://www.googleapis.com/auth/spreadsheets'],
});

// Tao Sheets client
const sheets = google.sheets({ version: 'v4', auth });

// San sang goi API!
console.log('Google Sheets API client initialized');

Scopes quan trong:

Scope Quyền Khi nào dùng
.../spreadsheets.readonly Chỉ đọc Dashboard, báo cáo
.../spreadsheets Đọc + Ghi CRUD data, format
.../drive Full Drive access Tạo/xóa spreadsheet
.../drive.file Chỉ file do app tạo Tạo spreadsheet mới

3.2 OAuth 2.0 Authentication (User-facing app)

Khi ứng dụng cần truy cập Google Sheets của người dùng cuối (user phải login và đồng ý), bạn dùng OAuth 2.0. Quy trình gồm 4 bước:

  1. Tạo OAuth 2.0 Client ID trên Google Cloud Console (Web Application type)
  2. Redirect user tới Google login page với consent screen
  3. User đăng nhập và grant permission → Google trả về authorization code
  4. Server dùng code để exchange lấy access token + refresh token
const { google } = require('googleapis');

// Tao OAuth2 client
const oauth2Client = new google.auth.OAuth2(
  process.env.GOOGLE_CLIENT_ID,
  process.env.GOOGLE_CLIENT_SECRET,
  'http://localhost:3000/auth/google/callback'  // redirect URI
);

// Buoc 1: Tao URL de redirect user
const authUrl = oauth2Client.generateAuthUrl({
  access_type: 'offline',  // de nhan refresh_token
  scope: ['https://www.googleapis.com/auth/spreadsheets.readonly'],
});
console.log('Redirect user to:', authUrl);

// Buoc 2: Sau khi user dong y, Google redirect ve voi ?code=xxx
// Server lay code tu query string roi exchange lay token
async function handleCallback(code) {
  const { tokens } = await oauth2Client.getToken(code);
  oauth2Client.setCredentials(tokens);

  // Luu tokens vao database de dung lai sau
  // tokens.access_token - het han sau 1 gio
  // tokens.refresh_token - dung de lay access_token moi

  const sheets = google.sheets({ version: 'v4', auth: oauth2Client });
  // Gio co the goi API voi quyen cua user
  return sheets;
}

Khi nao dung Service Account vs OAuth 2.0?

  • Service Account: Backend script, cron job, webhook handler, server-to-server integration. Sheets thuoc ve to chuc/team cua ban.
  • OAuth 2.0: Ung dung SaaS cho phep user ket noi Google Sheets cua ho. VD: Zapier, Make.com, Retool.
  • API Key: Chi doc data tu sheet da public (published to web). Khong can auth.

Phan 4: CRUD Operations voi JavaScript/Node.js

Day la phan chinh cua bai viet - huong dan chi tiet cach doc, ghi, cap nhat va xoa du lieu tren Google Sheets bang Node.js. Tat ca code deu dung googleapis official library.

4.1 Read Data (Doc du lieu)

Doc 1 range cu the:

const { google } = require('googleapis');

async function readData() {
  const auth = new google.auth.GoogleAuth({
    keyFile: './service-account-key.json',
    scopes: ['https://www.googleapis.com/auth/spreadsheets.readonly'],
  });

  const sheets = google.sheets({ version: 'v4', auth });
  const spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms';

  // Doc du lieu tu Sheet1, cot A den E, dong 1 den 100
  const response = await sheets.spreadsheets.values.get({
    spreadsheetId,
    range: 'Sheet1!A1:E100',
  });

  const rows = response.data.values;
  if (!rows || rows.length === 0) {
    console.log('Khong co du lieu.');
    return;
  }

  // rows la mang 2 chieu: [[row1], [row2], ...]
  console.log('Header:', rows[0]);  // ['Ma SP', 'Ten SP', 'Gia', 'Ton kho', 'Danh muc']

  // Duyet qua cac dong du lieu (bo header)
  for (let i = 1; i < rows.length; i++) {
    const [maSP, tenSP, gia, tonKho, danhMuc] = rows[i];
    console.log('San pham: ' + tenSP + ' - Gia: ' + gia + ' - Ton: ' + tonKho);
  }

  return rows;
}

readData();

Doc nhieu range cung luc (Batch Get):

async function batchRead() {
  const auth = new google.auth.GoogleAuth({
    keyFile: './service-account-key.json',
    scopes: ['https://www.googleapis.com/auth/spreadsheets.readonly'],
  });

  const sheets = google.sheets({ version: 'v4', auth });
  const spreadsheetId = 'YOUR_SPREADSHEET_ID';

  // Doc nhieu range 1 lan - tiet kiem API quota
  const response = await sheets.spreadsheets.values.batchGet({
    spreadsheetId,
    ranges: [
      'DonHang!A1:F100',      // Sheet Don Hang
      'SanPham!A1:D50',       // Sheet San Pham
      'KhachHang!A1:C200',    // Sheet Khach Hang
    ],
  });

  const [donHang, sanPham, khachHang] = response.data.valueRanges;
  console.log('Don hang:', donHang.values.length, 'dong');
  console.log('San pham:', sanPham.values.length, 'dong');
  console.log('Khach hang:', khachHang.values.length, 'dong');

  return response.data.valueRanges;
}

batchRead();

4.2 Write Data (Ghi du lieu)

Ghi de 1 range (Update):

async function writeData() {
  const auth = new google.auth.GoogleAuth({
    keyFile: './service-account-key.json',
    scopes: ['https://www.googleapis.com/auth/spreadsheets'],
  });

  const sheets = google.sheets({ version: 'v4', auth });
  const spreadsheetId = 'YOUR_SPREADSHEET_ID';

  // Ghi de du lieu vao range cu the
  const response = await sheets.spreadsheets.values.update({
    spreadsheetId,
    range: 'Sheet1!A1:C3',
    valueInputOption: 'USER_ENTERED',  // Xu ly cong thuc & format nhu user nhap
    requestBody: {
      values: [
        ['Ma SP', 'Ten San Pham', 'Gia'],           // Header
        ['SP001', 'Ao thun nam', '150000'],          // Dong 1
        ['SP002', 'Quan jean nu', '350000'],         // Dong 2
      ],
    },
  });

  console.log('Updated ' + response.data.updatedCells + ' cells');
  // Output: Updated 9 cells
}

writeData();

Them dong moi vao cuoi (Append) - phu hop nhat cho form website:

async function appendData(formData) {
  const auth = new google.auth.GoogleAuth({
    keyFile: './service-account-key.json',
    scopes: ['https://www.googleapis.com/auth/spreadsheets'],
  });

  const sheets = google.sheets({ version: 'v4', auth });
  const spreadsheetId = 'YOUR_SPREADSHEET_ID';

  // Append - them dong moi vao cuoi bang
  const response = await sheets.spreadsheets.values.append({
    spreadsheetId,
    range: 'DonHang!A:F',  // Chi can chi range, API tu tim dong trong cuoi
    valueInputOption: 'USER_ENTERED',
    insertDataOption: 'INSERT_ROWS',  // Chen dong moi
    requestBody: {
      values: [
        [
          formData.orderId,
          formData.customerName,
          formData.phone,
          formData.product,
          formData.quantity,
          new Date().toLocaleDateString('vi-VN'),  // Ngay dat
        ],
      ],
    },
  });

  console.log('Appended ' + response.data.updates.updatedRows + ' rows');
  return response.data;
}

// Su dung:
appendData({
  orderId: 'DH001',
  customerName: 'Nguyen Van A',
  phone: '0901234567',
  product: 'Ao thun nam',
  quantity: 2,
});

Tip: valueInputOption co 2 gia tri

  • USER_ENTERED: Xu ly nhu user nhap - nhan dien cong thuc (=SUM), date format, number format. Khuyen dung cho hau het truong hop.
  • RAW: Ghi nguyen gia tri string, khong xu ly gi. Dung khi muon ghi chuoi "=SUM(A1:A10)" ma khong bi chuyen thanh cong thuc.

4.3 Batch Update (Cap nhat nhieu range cung luc)

async function batchUpdate() {
  const auth = new google.auth.GoogleAuth({
    keyFile: './service-account-key.json',
    scopes: ['https://www.googleapis.com/auth/spreadsheets'],
  });

  const sheets = google.sheets({ version: 'v4', auth });
  const spreadsheetId = 'YOUR_SPREADSHEET_ID';

  // Cap nhat nhieu range trong 1 request duy nhat
  const response = await sheets.spreadsheets.values.batchUpdate({
    spreadsheetId,
    requestBody: {
      valueInputOption: 'USER_ENTERED',
      data: [
        {
          range: 'TongHop!A1',
          values: [['Cap nhat luc: ' + new Date().toLocaleString('vi-VN')]],
        },
        {
          range: 'TongHop!B5:D5',
          values: [['1500', '2300', '800']],  // Tong don hang, doanh thu, loi nhuan
        },
        {
          range: 'SanPham!D2:D4',
          values: [['120'], ['85'], ['200']],  // Cap nhat ton kho 3 san pham
        },
      ],
    },
  });

  console.log('Batch updated ' + response.data.totalUpdatedCells + ' cells');
  // Tiet kiem duoc 3 API calls xuong con 1!
}

batchUpdate();

4.4 Create & Delete Sheets (Tabs)

async function manageSheets() {
  const auth = new google.auth.GoogleAuth({
    keyFile: './service-account-key.json',
    scopes: ['https://www.googleapis.com/auth/spreadsheets'],
  });

  const sheets = google.sheets({ version: 'v4', auth });
  const spreadsheetId = 'YOUR_SPREADSHEET_ID';

  // Tao sheet (tab) moi
  const addResponse = await sheets.spreadsheets.batchUpdate({
    spreadsheetId,
    requestBody: {
      requests: [
        {
          addSheet: {
            properties: {
              title: 'BaoCao_Thang02_2026',
              gridProperties: {
                rowCount: 1000,
                columnCount: 20,
              },
            },
          },
        },
      ],
    },
  });

  const newSheetId = addResponse.data.replies[0].addSheet.properties.sheetId;
  console.log('Created sheet with ID:', newSheetId);

  // Xoa sheet theo sheetId
  await sheets.spreadsheets.batchUpdate({
    spreadsheetId,
    requestBody: {
      requests: [
        {
          deleteSheet: {
            sheetId: newSheetId,  // ID cua sheet can xoa
          },
        },
      ],
    },
  });

  console.log('Deleted sheet:', newSheetId);
}

manageSheets();

4.5 Format Cells (Dinh dang o)

async function formatCells() {
  const auth = new google.auth.GoogleAuth({
    keyFile: './service-account-key.json',
    scopes: ['https://www.googleapis.com/auth/spreadsheets'],
  });

  const sheets = google.sheets({ version: 'v4', auth });
  const spreadsheetId = 'YOUR_SPREADSHEET_ID';

  await sheets.spreadsheets.batchUpdate({
    spreadsheetId,
    requestBody: {
      requests: [
        // Bold header row
        {
          repeatCell: {
            range: {
              sheetId: 0,
              startRowIndex: 0,
              endRowIndex: 1,
            },
            cell: {
              userEnteredFormat: {
                backgroundColor: { red: 0.2, green: 0.4, blue: 0.8 },
                textFormat: {
                  bold: true,
                  foregroundColor: { red: 1, green: 1, blue: 1 },
                  fontSize: 12,
                },
              },
            },
            fields: 'userEnteredFormat(backgroundColor,textFormat)',
          },
        },
        // Auto resize columns
        {
          autoResizeDimensions: {
            dimensions: {
              sheetId: 0,
              dimension: 'COLUMNS',
              startIndex: 0,
              endIndex: 10,
            },
          },
        },
      ],
    },
  });

  console.log('Formatted header and auto-resized columns');
}

formatCells();

Phan 5: Vi du thuc te - Tich hop Form Website vao Google Sheets

Day la vi du hoan chinh: xay dung API endpoint nhan du lieu tu form website va ghi vao Google Sheets. Tech stack: Node.js + Express.

5.1 Cau truc project

form-to-sheets/
  package.json
  .env
  service-account-key.json    (KHONG commit file nay!)
  server.js
  public/
    index.html                (Form HTML)

5.2 File .env

PORT=3000
SPREADSHEET_ID=1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms
SHEET_NAME=DonHang
GOOGLE_SERVICE_ACCOUNT_KEY=./service-account-key.json

5.3 server.js - Backend hoan chinh

const express = require('express');
const { google } = require('googleapis');
const cors = require('cors');
require('dotenv').config();

const app = express();
app.use(cors());
app.use(express.json());
app.use(express.static('public'));

// Khoi tao Google Sheets client
let sheetsClient;

async function initSheetsClient() {
  const auth = new google.auth.GoogleAuth({
    keyFile: process.env.GOOGLE_SERVICE_ACCOUNT_KEY,
    scopes: ['https://www.googleapis.com/auth/spreadsheets'],
  });
  sheetsClient = google.sheets({ version: 'v4', auth });
  console.log('Google Sheets client initialized');
}

// API endpoint: Nhan form data va ghi vao Sheets
app.post('/api/submit-order', async (req, res) => {
  try {
    const { customerName, phone, email, product, quantity, note } = req.body;

    // Validate input
    if (!customerName || !phone || !product) {
      return res.status(400).json({
        error: 'Thieu thong tin bat buoc: customerName, phone, product'
      });
    }

    // Tao ma don hang tu dong
    const orderId = 'DH' + Date.now().toString().slice(-8);
    const orderDate = new Date().toLocaleString('vi-VN', { timeZone: 'Asia/Ho_Chi_Minh' });

    // Ghi vao Google Sheets
    await sheetsClient.spreadsheets.values.append({
      spreadsheetId: process.env.SPREADSHEET_ID,
      range: process.env.SHEET_NAME + '!A:H',
      valueInputOption: 'USER_ENTERED',
      insertDataOption: 'INSERT_ROWS',
      requestBody: {
        values: [[
          orderId,
          customerName,
          phone,
          email || '',
          product,
          quantity || 1,
          note || '',
          orderDate,
        ]],
      },
    });

    console.log('Order saved: ' + orderId + ' - ' + customerName);

    res.json({
      success: true,
      message: 'Don hang da duoc luu thanh cong!',
      orderId: orderId,
    });

  } catch (error) {
    console.error('Error saving order:', error.message);
    res.status(500).json({
      error: 'Loi he thong. Vui long thu lai sau.'
    });
  }
});

// API endpoint: Doc danh sach don hang
app.get('/api/orders', async (req, res) => {
  try {
    const response = await sheetsClient.spreadsheets.values.get({
      spreadsheetId: process.env.SPREADSHEET_ID,
      range: process.env.SHEET_NAME + '!A:H',
    });

    const rows = response.data.values || [];
    if (rows.length <= 1) {
      return res.json({ orders: [], total: 0 });
    }

    const headers = rows[0];
    const orders = rows.slice(1).map(function(row) {
      var order = {};
      headers.forEach(function(header, index) {
        order[header] = row[index] || '';
      });
      return order;
    });

    res.json({ orders: orders, total: orders.length });

  } catch (error) {
    console.error('Error reading orders:', error.message);
    res.status(500).json({ error: 'Loi doc du lieu' });
  }
});

// Khoi dong server
const PORT = process.env.PORT || 3000;
initSheetsClient().then(function() {
  app.listen(PORT, function() {
    console.log('Server running on port ' + PORT);
  });
});

5.4 Frontend Form (public/index.html)

<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8">
  <title>Form Dat Hang</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 500px; margin: 50px auto; }
    input, textarea { width: 100%; padding: 10px; margin: 5px 0 15px; border: 1px solid #ddd; border-radius: 5px; }
    button { background: #4285f4; color: white; padding: 12px 30px; border: none; border-radius: 5px; cursor: pointer; }
    button:hover { background: #3367d6; }
    .success { color: green; font-weight: bold; }
    .error { color: red; }
  </style>
</head>
<body>
  <h1>Form Dat Hang</h1>
  <form id="orderForm">
    <label>Ho ten (*)</label>
    <input type="text" name="customerName" required>

    <label>So dien thoai (*)</label>
    <input type="tel" name="phone" required>

    <label>Email</label>
    <input type="email" name="email">

    <label>San pham (*)</label>
    <input type="text" name="product" required>

    <label>So luong</label>
    <input type="number" name="quantity" value="1" min="1">

    <label>Ghi chu</label>
    <textarea name="note" rows="3"></textarea>

    <button type="submit">Gui Don Hang</button>
  </form>
  <div id="result"></div>

  <script>
  document.getElementById('orderForm').addEventListener('submit', function(e) {
    e.preventDefault();
    var formData = new FormData(e.target);
    var data = {};
    formData.forEach(function(value, key) { data[key] = value; });

    fetch('/api/submit-order', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    })
    .then(function(res) { return res.json(); })
    .then(function(result) {
      if (result.success) {
        document.getElementById('result').innerHTML =
          '<p class="success">Da gui thanh cong! Ma don: ' + result.orderId + '</p>';
        e.target.reset();
      } else {
        document.getElementById('result').innerHTML =
          '<p class="error">Loi: ' + result.error + '</p>';
      }
    })
    .catch(function(err) {
      document.getElementById('result').innerHTML =
        '<p class="error">Loi ket noi server</p>';
    });
  });
  </script>
</body>
</html>

Ket qua: Form → Google Sheets

Khi user dien form va nhan "Gui Don Hang":

  1. Frontend gui POST request den /api/submit-order
  2. Backend validate data, tao ma don hang tu dong
  3. Backend goi Google Sheets API append de them dong moi
  4. Du lieu xuat hien trong Google Sheets ngay lap tuc (do tre < 1 giay)
  5. Team van hanh mo Sheets tren dien thoai/may tinh de xu ly don

Phan 6: Python Examples voi gspread

Neu ban lam viec voi Python (Data Science, automation scripts, Django/Flask backend), thu vien gspread la cach don gian nhat de tuong tac voi Google Sheets.

6.1 Cai dat va xac thuc

# Cai dat
pip install gspread oauth2client

# Hoac dung google-auth (moi hon)
pip install gspread google-auth
import gspread
from google.oauth2.service_account import Credentials

# Xac thuc voi Service Account
scopes = [
    'https://www.googleapis.com/auth/spreadsheets',
    'https://www.googleapis.com/auth/drive'
]

credentials = Credentials.from_service_account_file(
    'service-account-key.json',
    scopes=scopes
)

gc = gspread.authorize(credentials)

# Mo spreadsheet bang URL hoac ID
spreadsheet = gc.open_by_key('YOUR_SPREADSHEET_ID')
# Hoac: spreadsheet = gc.open('Ten File Google Sheets')

# Chon sheet (tab)
worksheet = spreadsheet.sheet1  # Sheet dau tien
# Hoac: worksheet = spreadsheet.worksheet('DonHang')

print('Connected to:', spreadsheet.title)

6.2 CRUD voi gspread

# === DOC DU LIEU ===

# Doc tat ca du lieu
all_data = worksheet.get_all_values()
print('Tong so dong:', len(all_data))

# Doc nhu dictionary (dong 1 lam key)
records = worksheet.get_all_records()
for record in records:
    print(record['Ten SP'], '-', record['Gia'])

# Doc 1 o cu the
cell_value = worksheet.acell('B2').value
print('Gia tri o B2:', cell_value)

# Doc 1 range
range_data = worksheet.get('A1:D10')
print('Range A1:D10:', range_data)


# === GHI DU LIEU ===

# Ghi 1 o
worksheet.update_acell('A1', 'Ma San Pham')

# Ghi 1 range
worksheet.update('A1:C3', [
    ['Ma SP', 'Ten SP', 'Gia'],
    ['SP001', 'Ao thun', '150000'],
    ['SP002', 'Quan jean', '350000'],
])

# Append dong moi (them vao cuoi)
worksheet.append_row(['SP003', 'Giay the thao', '500000', '50', 'Giay dep'])
# Append nhieu dong
worksheet.append_rows([
    ['SP004', 'Mu luoi trai', '120000', '200', 'Phu kien'],
    ['SP005', 'Balo laptop', '450000', '30', 'Phu kien'],
])


# === TIM KIEM ===

# Tim o chua gia tri cu the
cell = worksheet.find('SP001')
print('Tim thay SP001 tai dong ' + str(cell.row) + ', cot ' + str(cell.col))

# Tim tat ca o chua "Ao"
cells = worksheet.findall('Ao')
print('Tim thay ' + str(len(cells)) + ' ket qua')


# === XOA ===

# Xoa dong thu 5
worksheet.delete_rows(5)

# Xoa nhieu dong (dong 3 den 7)
worksheet.delete_rows(3, 7)

gspread vs googleapis: Nen dung cai nao?

  • gspread: API don gian, Pythonic, it code hon. Phu hop cho scripts, data analysis, automation.
  • googleapis (Python): Official library, day du tinh nang, tot cho production app can fine-grained control.
  • Ca 2 deu dung cung Service Account credentials - khac nhau o syntax goi API.

Phan 7: Rate Limits & Quotas - Dieu ban phai biet

Google Sheets API co cac gioi han su dung (quotas) de dam bao hieu suat cho tat ca nguoi dung. Neu vuot qua gioi han, ban se nhan loi 429 Too Many Requests. Day la bang gioi han chi tiet:

Loai Quota Gioi han Don vi
Read requests 300 per minute per project
Write requests 300 per minute per project
Read requests per user 60 per minute per user
Write requests per user 60 per minute per user

Cach xu ly rate limiting:

// Retry voi exponential backoff
async function callWithRetry(apiCall, maxRetries) {
  maxRetries = maxRetries || 5;

  for (var attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await apiCall();
    } catch (error) {
      if (error.code === 429 && attempt < maxRetries) {
        // Rate limited - doi roi thu lai
        var waitTime = Math.pow(2, attempt) * 1000;  // 2s, 4s, 8s, 16s, 32s
        console.log('Rate limited. Retry sau ' + (waitTime/1000) + 's (lan ' + attempt + '/' + maxRetries + ')');
        await new Promise(function(resolve) { setTimeout(resolve, waitTime); });
      } else {
        throw error;
      }
    }
  }
}

// Su dung:
var data = await callWithRetry(function() {
  return sheets.spreadsheets.values.get({
    spreadsheetId: spreadsheetId,
    range: 'Sheet1!A1:Z1000',
  });
});
console.log('Got data:', data.data.values.length, 'rows');

5 meo giam API calls

  1. Batch operations: Dung batchGet/batchUpdate thay vi goi rieng le. 10 requests → 1 request.
  2. Cache data: Doc 1 lan, luu vao cache (Redis/memory), chi refresh khi can thiet.
  3. Webhook thay polling: Thay vi doc Sheets moi 30 giay, dung Apps Script trigger gui webhook khi co thay doi.
  4. Append thay Update: Khi ghi nhieu dong, dung 1 append voi mang nhieu dong thay vi append tung dong.
  5. Gioi han range: Chi doc range can thiet (A1:E100) thay vi doc toan bo sheet (A:Z).

Phan 8: Bao mat API - Best Practices

Bao mat la yeu to cuc ky quan trong khi lam viec voi API. Mot sai lam nho co the dan den ro ri du lieu hoac bi tan cong. Day la cac best practices:

8.1 Bao ve Service Account Key

  • 1.

    KHONG BAO GIO commit file JSON key vao Git. Them vao .gitignore: service-account-key.json

  • 2.

    Dung environment variables trong production. Luu client_email va private_key trong ENV thay vi file.

  • 3.

    Rotate key dinh ky. Moi 90 ngay, tao key moi va xoa key cu tren Google Cloud Console.

  • 4.

    Mot Service Account cho moi ung dung. Khong dung chung SA giua nhieu project.

  • 5.

    Gioi han scope toi thieu. Chi dung spreadsheets.readonly neu chi can doc.

8.2 Restrict API Key

Neu dung API Key (cho public sheets), PHAI restrict:

  1. Application restrictions: Gioi han theo HTTP referer (website), IP address (server), hoac Android/iOS app.
  2. API restrictions: Chi cho phep goi Google Sheets API, khong cho goi cac API khac.
  3. Quota restrictions: Dat gioi han so request/ngay thap hon mac dinh.

8.3 Google Sheets Permissions

Ngoai bao mat API, hay kiem soat quyen truy cap file Sheets:

Nguyen tac Chi tiet
Least privilege Share Viewer neu chi can doc, Editor neu can ghi. Khong share Owner.
Protected ranges Khoa cac range quan trong (header, cong thuc) de Service Account khong ghi de nham.
Audit trail Dung Version History cua Sheets de theo doi thay doi. Moi edit tu API deu duoc ghi lai.
Separate sheets Dung sheet rieng cho API ghi (VD: "API_Input") va sheet rieng cho bao cao. Tranh ghi de du lieu thu cong.

Phan 9: So sanh API vs Apps Script vs IMPORTDATA

Google cung cap nhieu cach de tuong tac voi Sheets tu ben ngoai. Day la bang so sanh chi tiet giup ban chon dung cong cu:

Tieu chi Sheets API Apps Script IMPORTDATA/IMPORTXML
Ngon ngu Bat ky (JS, Python, Go, Java...) JavaScript (Google V8) Cong thuc trong Sheets
Chay o dau Server cua ban Google server Trong spreadsheet
Xac thuc Service Account / OAuth2 Tu dong (bound to sheet) Khong can
Do phuc tap Cao (setup project, auth, deploy) Trung binh Thap (chi la cong thuc)
Hieu suat Cao nhat Trung binh Thap (refresh moi 1-2h)
Use case chinh Tich hop website/app, ETL, automation Automation trong Sheets, webhook Import data tu CSV/XML public

Khi nao dung cai nao?

  • Sheets API: Khi can tich hop voi website/app ben ngoai, xu ly luong du lieu lon, can kiem soat hoan toan ve performance va error handling.
  • Apps Script: Khi logic xu ly don gian, chay dinh ky (trigger), khong can server rieng. VD: gui email hang ngay, clean data, custom menu.
  • IMPORTDATA: Khi chi can import 1 file CSV/XML public vao Sheets, khong can lap trinh. VD: import gia vang, ty gia, thoi tiet.
  • Ket hop: Nhieu project dung ca API (frontend form ghi data) + Apps Script (trigger gui email khi co dong moi). Day la pattern pho bien nhat.

Phan 10: Advanced Tips & Patterns

10.1 Webhook Pattern: Apps Script nhan du lieu tu ben ngoai

Ban co the deploy Apps Script nhu Web App de nhan HTTP POST request tu bat ky nguon nao (webhook Shopify, Stripe, Facebook Lead Ads...):

// Deploy Apps Script nhu Web App nhan webhook
function doPost(e) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Webhook_Data');
  var data = JSON.parse(e.postData.contents);

  // Ghi du lieu webhook vao sheet
  sheet.appendRow([
    new Date().toLocaleString('vi-VN'),
    data.event_type || 'unknown',
    data.customer_name || '',
    data.customer_email || '',
    data.amount || 0,
    JSON.stringify(data),  // Raw JSON de debug
  ]);

  return ContentService
    .createTextOutput(JSON.stringify({ status: 'ok' }))
    .setMimeType(ContentService.MimeType.JSON);
}

// Deploy: Publish > Deploy as web app
// Execute as: Me
// Who has access: Anyone (neu nhan webhook tu ben ngoai)

10.2 Caching Pattern: Giam API calls voi Redis

const Redis = require('ioredis');
const redis = new Redis();

async function getSheetDataCached(spreadsheetId, range, ttlSeconds) {
  ttlSeconds = ttlSeconds || 300;  // Cache 5 phut
  var cacheKey = 'sheets:' + spreadsheetId + ':' + range;

  // Kiem tra cache
  var cached = await redis.get(cacheKey);
  if (cached) {
    console.log('Cache hit for', range);
    return JSON.parse(cached);
  }

  // Cache miss - goi API
  console.log('Cache miss for', range, '- calling API');
  var response = await sheets.spreadsheets.values.get({
    spreadsheetId: spreadsheetId,
    range: range,
  });

  var data = response.data.values;

  // Luu vao cache
  await redis.setex(cacheKey, ttlSeconds, JSON.stringify(data));

  return data;
}

// Su dung - API chi duoc goi 1 lan moi 5 phut
var products = await getSheetDataCached(
  'YOUR_SPREADSHEET_ID',
  'SanPham!A1:E100',
  300
);

10.3 Queue Pattern: Xu ly nhieu request dong thoi

// Khi website co nhieu user submit form cung luc
// Thay vi goi API cho moi request, gom lai roi batch append

var pendingRows = [];
var flushTimer = null;

function queueRow(rowData) {
  pendingRows.push(rowData);

  // Flush sau 2 giay hoac khi du 50 rows
  if (pendingRows.length >= 50) {
    flushToSheets();
  } else if (!flushTimer) {
    flushTimer = setTimeout(flushToSheets, 2000);
  }
}

async function flushToSheets() {
  if (pendingRows.length === 0) return;

  var rowsToFlush = pendingRows.splice(0);  // Lay het va xoa
  clearTimeout(flushTimer);
  flushTimer = null;

  try {
    await sheets.spreadsheets.values.append({
      spreadsheetId: process.env.SPREADSHEET_ID,
      range: 'DonHang!A:H',
      valueInputOption: 'USER_ENTERED',
      insertDataOption: 'INSERT_ROWS',
      requestBody: {
        values: rowsToFlush,
      },
    });
    console.log('Flushed ' + rowsToFlush.length + ' rows to Sheets');
  } catch (error) {
    console.error('Flush failed:', error.message);
    // Push lai vao queue de thu lai
    pendingRows.unshift.apply(pendingRows, rowsToFlush);
  }
}

// Su dung trong Express endpoint:
// app.post('/api/order', function(req, res) {
//   queueRow([orderId, name, phone, product, qty, date]);
//   res.json({ success: true });
// });

10.4 Error Handling Pattern

async function safeApiCall(apiFunction) {
  try {
    return await apiFunction();
  } catch (error) {
    var code = error.code || error.response?.status;

    switch(code) {
      case 400:
        console.error('Bad Request - Kiem tra lai range hoac data format');
        break;
      case 401:
        console.error('Unauthorized - Service Account key het han hoac sai');
        break;
      case 403:
        console.error('Forbidden - Service Account chua duoc share vao Sheets');
        break;
      case 404:
        console.error('Not Found - Spreadsheet ID sai hoac da bi xoa');
        break;
      case 429:
        console.error('Rate Limited - Qua nhieu request, can doi roi thu lai');
        break;
      default:
        console.error('Unknown error:', code, error.message);
    }

    throw error;
  }
}

Phan 11: FAQ - Cau hoi thuong gap

Google Sheets API co mat phi khong?

Google Sheets API hoan toan mien phi su dung. Ban khong can tra phi cho Google Cloud chi vi goi Sheets API. Tuy nhien, neu vuot qua quota mac dinh (300 requests/min/project), ban co the yeu cau tang quota - viec nay cung mien phi nhung can fill form va doi Google review (thuong 2-5 ngay lam viec).

Do tre (latency) khi goi API la bao nhieu?

Trung binh 200-500ms cho moi request doc/ghi don gian (voi server o chau A). Voi batch operations doc/ghi nhieu range, co the mat 500ms-2s. De giam latency: (1) Dung server gan Google datacenter (us-central1, asia-east1), (2) Giam kich thuoc range doc, (3) Dung batchGet thay vi nhieu get rieng le, (4) Cache data doc thuong xuyen.

Nhieu user ghi vao cung 1 sheet cung luc co bi loi khong?

Google Sheets co co che lock noi bo xu ly concurrent writes. Neu 2 request ghi vao cung 1 range cung luc, request den sau se ghi de request truoc (last-write-wins). Neu ghi vao range khac nhau hoac dung append, se khong bi xung dot. Best practice: Dung append thay vi update khi nhieu nguoi ghi cung luc, va dung queue pattern nhu da trinh bay o phan 10.3.

Co the nhan webhook khi sheet thay doi khong?

Google Sheets API khong co webhook/push notification truc tiep. Tuy nhien co 2 cach work around: (1) Dung Apps Script onEdit trigger de gui HTTP request (webhook) toi server cua ban moi khi co edit, (2) Dung Google Drive API push notification (watch changes) - API nay thong bao khi file thay doi nhung khong chi tiet cell nao. Cach 1 pho bien va don gian hon.

Co the goi Google Sheets API tu mobile app khong?

Khong nen goi truc tiep tu mobile app vi se phai nhung Service Account key vao app (de bi decompile va lo key). Thay vao do, mobile app nen goi API cua server backend cua ban, server backend se goi Google Sheets API. Pattern: Mobile App → Your Backend API → Google Sheets API. Viec nay cung giup ban validate data, kiem soat rate limit, va them cac logic nghiep vu truoc khi ghi vao Sheets.

Tong ket va buoc tiep theo

Google Sheets API la cong cu manh me giup ban bien Google Sheets tu mot bang tinh don gian thanh backend database lam viec cho website va ung dung. Voi kien thuc tu bai viet nay, ban da co the:

  • Setup Google Cloud project va enable Sheets API
  • Xac thuc bang Service Account (server-to-server) va OAuth2 (user-facing)
  • Doc, ghi, cap nhat, xoa du lieu voi Node.js va Python
  • Xay dung he thong form website tu dong ghi vao Sheets
  • Xu ly rate limits voi retry + exponential backoff
  • Bao mat API key va Service Account dung cach
  • Ap dung advanced patterns: cache, queue, webhook, error handling

Buoc tiep theo:

  1. Thuc hanh ngay: Tao 1 Google Cloud project, enable API, tao Service Account, goi thu API doc 1 sheet.
  2. Xay dung project thuc te: Bat dau voi vi du form website → Sheets o phan 5. Deploy len Vercel/Railway/Render mien phi.
  3. Tim hieu them: Doc bai Apps Script tu co ban den nang cao de ket hop API + Apps Script tao he thong hoan chinh.
  4. Tham khao: Xu ly du lieu lon tren Google Sheets de hieu gioi han va toi uu hieu suat khi dung API voi du lieu lon.

Ban muon giai phap tich hop san?

Neu ban khong muon tu code API tu dau, SheetStore da tich hop san Google Sheets API giup ban:

  • Quan ly ban hang: Don hang tu website tu dong dong bo vao Google Sheets - team van hanh lam viec ngay tren Sheets.
  • Quan ly kho hang: Ton kho cap nhat realtime giua website va Sheets.
  • Bao cao tu dong: Dashboard doanh thu, san pham ban chay tu dong cap nhat tren Google Sheets.
  • CRM khach hang: Thong tin khach hang dong bo giua website va Sheets.

Chia sẻ bài viết:

Tuân Hoang

Tuân Hoang

Đội ngũ SheetStore

Bạn thấy bài viết hữu ích?

Đăng ký nhận thông báo khi có bài viết mới.

Nhận thông báo khi có bài viết mới. Không spam, hứa luôn! 😊

Bình luận (0)

Vui lòng đăng nhập để tham gia thảo luận