คู่มือ DigitalOcean API v2 — Automation สำหรับนักพัฒนา
A practical developer's guide to the DigitalOcean API v2 — authentication, curl examples for Droplets, DNS, and Firewalls, rate limiting, and automation scripting.
สารบัญ
ภาพรวม REST API v2
DigitalOcean API v2 เป็น REST API มาตรฐานที่สื่อสารผ่าน HTTP ด้วยรูปแบบข้อมูล JSON ทั้งฝั่ง request และ response โดยมี base URL คือ https://api.digitalocean.com/v2/ และแยก resource ตามฟีเจอร์ เช่น /v2/droplets, /v2/domains, /v2/databases, /v2/kubernetes/clusters, /v2/load_balancers และ /v2/firewalls โครงสร้างนี้ทำให้แทบทุกฟีเจอร์ที่เห็นใน Control Panel มี endpoint ให้เรียกผ่านโค้ดได้โดยไม่ต้องเข้าเว็บคลิกเอง การยืนยันตัวตนใช้ Bearer token แนบไปกับ HTTP header Authorization: Bearer $TOKEN ทุก request (รายละเอียดการสร้าง token อยู่ในหัวข้อถัดไป) ส่วน method HTTP ก็ตรงตามหลัก REST ทั่วไปคือ GET สำหรับดึงข้อมูล, POST สำหรับสร้างใหม่, PUT/PATCH สำหรับแก้ไข และ DELETE สำหรับลบ ตัวอย่างเช่นการเรียกดูรายการ Droplet ทั้งหมดในบัญชีทำได้ด้วย curl -X GET -H "Authorization: Bearer $TOKEN" "https://api.digitalocean.com/v2/droplets" Response ที่ได้กลับมาจะเป็น JSON ที่ครอบด้วย key ของชื่อ resource เช่น droplets พร้อม object links และ meta บอกจำนวนทั้งหมด ส่วน pagination ของ list ที่มีจำนวนมากจะมี object links.pages บอก URL ของหน้าถัดไปและหน้าก่อนหน้า ทำให้ไม่ต้องคำนวณ offset เอง สำหรับคนที่ไม่อยากเขียน HTTP request ด้วยมือทุกครั้ง DigitalOcean มี client library ที่ทางการดูแลให้หลายภาษา เช่น godo สำหรับ Go และ pydo สำหรับ Python ซึ่งห่อ API v2 ไว้เป็นฟังก์ชันพร้อมใช้ รวมถึง CLI ชื่อ doctl ที่เป็นเครื่องมือ command line อย่างเป็นทางการสำหรับเรียก API นี้โดยไม่ต้องเขียน curl เอง เหมาะกับงานที่ต้องรันบ่อยๆ หรือใช้ในสคริปต์ shell เอกสารอ้างอิงฉบับเต็มของทุก endpoint อยู่ที่ developers.digitalocean.com ซึ่งควรเปิดเทียบคู่กับบทความนี้เสมอ เพราะแต่ละ resource มี field เฉพาะของตัวเอง เช่น Droplet ต้องระบุ size, image, region ส่วน Load Balancer ต้องระบุ forwarding_rules เป็นต้น การเข้าใจโครงสร้างพื้นฐานนี้ก่อนจะช่วยให้อ่านตัวอย่างโค้ดในหัวข้อถัดไปได้เร็วขึ้นมาก เพราะทุก endpoint ใช้ pattern เดียวกันคือ header, JSON body และ HTTP method ตามมาตรฐาน REST
DigitalOcean API v2 is a standard REST API that communicates over HTTP using JSON format for both request and response. It has a base URL of https://api.digitalocean.com/v2/ and separates resources by feature, such as /v2/droplets, /v2/domains, /v2/databases, /v2/kubernetes/clusters, /v2/load_balancers, and /v2/firewalls. This structure makes nearly every feature visible in the Control Panel callable through code without needing to log in to the web interface manually. Authentication uses a Bearer token included in the HTTP header Authorization: Bearer $TOKEN with every request (details on creating tokens are in the next section). HTTP methods follow standard REST conventions: GET for retrieving data, POST for creating new resources, PUT/PATCH for updates, and DELETE for removal. For example, retrieving all Droplets in an account can be done with curl -X GET -H "Authorization: Bearer $TOKEN" "https://api.digitalocean.com/v2/droplets". The response returned is JSON wrapped with a resource key such as droplets, along with object links and meta showing the total count. For lists with many items, the response includes links.pages object providing URLs for the next and previous pages, eliminating the need to calculate offsets manually. For those who prefer not to write HTTP requests by hand every time, DigitalOcean provides official client libraries for multiple languages: godo for Go and pydo for Python, which wrap the API v2 into ready-to-use functions. There's also an official CLI tool called doctl that serves as the command-line interface for this API without writing curl commands yourself—ideal for frequently run tasks or shell scripts. The complete API reference documentation is available at developers.digitalocean.com, which should be kept open alongside this article at all times, as each resource has its own specific fields. For instance, Droplets require size, image, and region specifications, while Load Balancers require forwarding_rules, and so on. Understanding this basic structure first helps you read the code examples in the following sections much faster, because every endpoint follows the same pattern: headers, JSON body, and HTTP method according to REST standards.
- Base URL หลักคือ https://api.digitalocean.com/v2/ ครอบคลุมแทบทุกฟีเจอร์ในบัญชี
- ยืนยันตัวตนด้วย Bearer token ผ่าน header Authorization ทุก request
- Response เป็น JSON เสมอ พร้อม pagination ผ่าน links.pages
- มี client library ทางการ (godo, pydo) และ CLI doctl ให้เลือกใช้แทนการเขียน curl เอง
- เอกสารฉบับเต็มอยู่ที่ developers.digitalocean.com ควรเปิดเทียบเคียงเสมอ
สร้าง Personal Access Token
จากที่เราทดสอบจริง — ก่อนเรียก API ได้ทุกครั้งต้องมี Personal Access Token ก่อน ซึ่งสร้างได้จากหน้า Control Panel ที่ cloud.digitalocean.com/account/api/tokens โดยกดปุ่ม Generate New Token ตั้งชื่อ token ให้สื่อความหมาย เช่น ระบุว่าใช้กับสคริปต์หรือเซิร์ฟเวอร์ไหน แล้วเลือก scope ว่าจะให้สิทธิ์ read-only หรือ full access (read and write) ถ้าสคริปต์แค่ดึงข้อมูลมาแสดงผลควรเลือก read-only เพื่อลดความเสี่ยงหาก token หลุด ส่วนถ้าต้องสร้าง/ลบ resource จริงต้องเลือก write ด้วย DigitalOcean ยังให้กำหนดวันหมดอายุของ token ได้ตั้งแต่ตอนสร้าง เช่น 30 วัน 90 วัน หรือไม่มีวันหมดอายุ ซึ่งสำหรับ token ที่ใช้ในสคริปต์ automation ระยะยาวควรตั้งวันหมดอายุและมีปฏิทินเตือนตัวเองให้สร้างใหม่ก่อนหมดอายุ เพื่อไม่ให้ระบบอัตโนมัติหยุดทำงานกะทันหันจาก token ที่หมดอายุโดยไม่รู้ตัว เมื่อกด Generate แล้ว ระบบจะแสดงค่า token ให้เห็นเพียงครั้งเดียวเท่านั้น ต้องคัดลอกเก็บไว้ทันที เพราะถ้าปิดหน้าไปแล้วจะไม่สามารถดูค่าเดิมซ้ำได้อีก ต้องสร้าง token ใหม่แทน วิธีเก็บที่แนะนำคือใส่ไว้ใน environment variable แทนการ hardcode ลงในไฟล์โค้ดโดยตรง เช่น export DIGITALOCEAN_TOKEN="dop_v1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" แล้วอ้างอิงผ่าน $DIGITALOCEAN_TOKEN ในสคริปต์หรือ CI/CD pipeline แทน วิธีนี้ช่วยให้ไม่ต้อง commit token ลง Git repository โดยไม่ได้ตั้งใจ ซึ่งเป็นสาเหตุการรั่วไหลของ token ที่พบบ่อยที่สุด หากใช้ Git ควรเพิ่มไฟล์ที่มี token ไว้ใน .gitignore เสมอ และถ้าพบว่า token หลุดออกไปแล้วไม่ว่าจะทางใด ให้กลับไปที่หน้า API Tokens แล้วกด Revoke ทันที เพราะ token ที่ยังไม่หมดอายุจะใช้เรียก API ได้เต็มสิทธิ์เหมือนรหัสผ่านบัญชี ทดสอบว่า token ใช้งานได้จริงหรือไม่ด้วยการยิง request ง่ายๆ ไปที่ endpoint บัญชี เช่น curl -X GET -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" "https://api.digitalocean.com/v2/account" ถ้า token ถูกต้องจะได้ JSON กลับมาพร้อมข้อมูลบัญชี เช่น อีเมลและสถานะการยืนยันตัวตน แต่ถ้า token ผิดหรือหมดอายุจะได้ HTTP status 401 พร้อมข้อความ error กลับมาแทน
- สร้างที่ cloud.digitalocean.com/account/api/tokens เลือก scope read-only หรือ read/write ตามงานที่ใช้
- ตั้งวันหมดอายุสำหรับ token ที่ใช้ระยะยาว ป้องกันสคริปต์หยุดทำงานกะทันหัน
- ค่า token แสดงให้เห็นครั้งเดียวตอนสร้าง ต้องคัดลอกเก็บทันที
- เก็บ token ใน environment variable ห้าม hardcode หรือ commit ลง Git
ตัวอย่าง curl: สร้าง/ลบ Droplet
การสร้าง Droplet ผ่าน API ทำได้ด้วยการยิง POST ไปที่ /v2/droplets พร้อมส่ง JSON body ที่ระบุอย่างน้อย 4 ค่าคือ name (ชื่อ), region (เช่น sgp1 สำหรับสิงคโปร์ ซึ่งเป็น region ที่ใกล้ผู้ใช้ในไทยที่สุด), size (slug ของขนาด เช่น s-1vcpu-1gb ซึ่งตรงกับแผน Basic Droplet 1 GiB RAM/1 vCPU ราคา $6/เดือน) และ image (เช่น ubuntu-24-04-x64) ตัวอย่างคำสั่งเต็ม curl -X POST -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" -H "Content-Type: application/json" -d '{"name":"web-01","region":"sgp1","size":"s-1vcpu-1gb","image":"ubuntu-24-04-x64"}' "https://api.digitalocean.com/v2/droplets" เมื่อยิงสำเร็จจะได้ HTTP status 202 Accepted กลับมาพร้อม JSON ของ Droplet ที่มีสถานะเป็น new และ id ของ action ที่กำลังสร้างอยู่ เนื่องจากการสร้าง Droplet ไม่ใช่งานที่เสร็จทันที ต้องตรวจสอบสถานะต่อได้ด้วยการ poll endpoint /v2/actions/$ACTION_ID จนกว่า field status จะเปลี่ยนเป็น completed จากนั้นค่อยเรียก GET /v2/droplets/$DROPLET_ID อีกครั้งเพื่อดู IP address ที่ได้รับจริง การดูรายการ Droplet ทั้งหมดในบัญชีทำได้ด้วย GET /v2/droplets เหมือนที่กล่าวไปในหัวข้อแรก ส่วนการลบ Droplet ใช้ DELETE พร้อมระบุ id ของ Droplet ที่จะลบต่อท้าย URL เช่น curl -X DELETE -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" "https://api.digitalocean.com/v2/droplets/12345678" คำสั่งลบสำเร็จจะได้ HTTP status 204 No Content กลับมา (ไม่มี response body) ซึ่งหมายความว่า Droplet ถูกทำลายถาวรแล้ว ข้อมูลบนดิสก์ทั้งหมดจะหายไปทันทีถ้าไม่ได้ทำ Snapshot ไว้ก่อน จึงควรเช็คให้แน่ใจว่าเป็น id ที่ถูกต้องก่อนยิง DELETE เสมอ โดยเฉพาะในสคริปต์อัตโนมัติที่ลบ Droplet เป็นชุด ควรมีขั้นตอน dry-run หรือ log รายการ id ที่จะลบออกมาดูก่อนสั่งลบจริง นอกจากลบทั้งตัวแล้ว ยังมี action อื่นที่เรียกผ่าน POST /v2/droplets/$ID/actions ได้ เช่น power_off, reboot, resize หรือ snapshot ซึ่งทุก action จะคืนค่าเป็น object ที่มี id ให้ track สถานะแบบเดียวกับตอนสร้าง Droplet
- สร้าง Droplet ด้วย POST /v2/droplets ระบุ name, region, size (เช่น s-1vcpu-1gb = $6/เดือน), image
- การสร้างเป็น async ต้อง poll /v2/actions/$ID จนสถานะเป็น completed
- ดูรายการทั้งหมดด้วย GET /v2/droplets
จัดการ DNS, Snapshot, Firewall ผ่าน API
นอกจาก Droplet แล้ว API v2 ยังครอบคลุมฟีเจอร์เสริมที่ใช้บ่อยในงาน automation อีกสามอย่างคือ DNS, Snapshot และ Firewall ฝั่ง DNS เริ่มจากการเพิ่มโดเมนเข้าระบบด้วย POST /v2/domains ระบุ name ของโดเมนและ ip_address ของ record A เริ่มต้น จากนั้นจัดการ record ย่อยเพิ่มเติมได้ที่ /v2/domains/$DOMAIN/records เช่นการเพิ่ม record ประเภท CNAME curl -X POST -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" -H "Content-Type: application/json" -d '{"type":"CNAME","name":"www","data":"@","ttl":3600}' "https://api.digitalocean.com/v2/domains/example.com/records" วิธีนี้มีประโยชน์มากเวลาต้องสร้าง subdomain จำนวนมากแบบอัตโนมัติ เช่นระบบที่ provision Droplet ใหม่แล้วต้องผูกโดเมนย่อยให้ลูกค้าทันทีโดยไม่ต้องเข้า Control Panel ทีละราย ฝั่ง Snapshot สร้างได้จาก action ของ Droplet ตามที่กล่าวในหัวข้อก่อนหน้า ด้วย POST /v2/droplets/$ID/actions พร้อม body {"type":"snapshot","name":"backup-2026-07-17"} ซึ่งเหมาะกับการตั้ง cron job สำรองข้อมูลอัตโนมัติทุกคืน โดยต้องรู้ไว้ว่า Snapshot มีค่าใช้จ่ายตามพื้นที่จริงที่ใช้ในอัตรา $0.06 ต่อ GiB ต่อเดือน ถ้าตั้งสคริปต์สร้าง snapshot ทุกวันโดยไม่ลบของเก่า จะมีค่าใช้จ่ายสะสมเพิ่มขึ้นเรื่อยๆ จึงควรเขียนสคริปต์ให้ลบ snapshot ที่เก่าเกินจำนวนที่กำหนดไว้ด้วย เช่น เก็บแค่ 7 วันล่าสุด โดยเรียก DELETE /v2/snapshots/$SNAPSHOT_ID กับตัวที่เก่ากว่านั้น ฝั่ง Firewall (Cloud Firewall ซึ่งไม่มีค่าใช้จ่ายเพิ่มเติม) สร้างได้ด้วย POST /v2/firewalls ระบุ inbound_rules, outbound_rules และ droplet_ids ที่จะผูกกฎนี้เข้าไป ตัวอย่างเช่นกฎเปิดเฉพาะพอร์ต 22 (SSH) และ 443 (HTTPS) curl -X POST -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" -H "Content-Type: application/json" -d '{"name":"web-fw","inbound_rules":[{"protocol":"tcp","ports":"22","sources":{"addresses":["0.0.0.0/0"]}},{"protocol":"tcp","ports":"443","sources":{"addresses":["0.0.0.0/0"]}}],"droplet_ids":[12345678]}' "https://api.digitalocean.com/v2/firewalls" การสร้าง Firewall ผ่าน API ทำให้กำหนดนโยบายความปลอดภัยมาตรฐานไว้เป็นโค้ดได้ (infrastructure as code แบบง่าย) แล้วนำไปผูกกับ Droplet ใหม่ทุกตัวที่ provision ผ่านสคริปต์เดียวกัน ลดโอกาสที่จะลืมตั้งค่า Firewall ตอนสร้างเซิร์ฟเวอร์ใหม่ด้วยมือ
- เพิ่มโดเมนด้วย POST /v2/domains แล้วจัดการ record ที่ /v2/domains/$DOMAIN/records
- สร้าง Snapshot ผ่าน Droplet action type snapshot ค่าใช้จ่าย $0.06/GiB/เดือน ควรลบของเก่าที่ไม่ใช้ด้วยสคริปต์
- ลบ Snapshot เก่าด้วย DELETE /v2/snapshots/$ID เพื่อคุมค่าใช้จ่าย
- สร้าง Firewall ด้วย POST /v2/firewalls ระบุ inbound/outbound rules และ droplet_ids (ไม่มีค่าใช้จ่ายเพิ่ม)
- ผูก Firewall มาตรฐานเข้ากับ Droplet ใหม่ทุกตัวผ่านสคริปต์เดียว ลดความเสี่ยงลืมตั้งค่า
Rate limit และการจัดการ error
API v2 มีการจำกัดจำนวน request ต่อช่วงเวลา (rate limiting) เพื่อป้องกันไม่ให้ผู้ใช้รายใดรายหนึ่งยิง request ถี่จนกระทบระบบส่วนกลาง วิธีตรวจสอบว่าเหลือโควตาเท่าไรไม่ต้องเดา เพราะทุก response จาก API จะแนบ HTTP header กลับมาบอกสถานะปัจจุบันเสมอ ได้แก่ RateLimit-Limit (โควตาสูงสุดในรอบ), RateLimit-Remaining (จำนวนที่เหลือ) และ RateLimit-Reset (เวลาที่โควตาจะรีเซ็ต เป็น Unix timestamp) สคริปต์ที่ยิง request จำนวนมากควรอ่านค่าจาก header เหล่านี้ทุกครั้งแล้วชะลอความเร็วเองเมื่อ RateLimit-Remaining ใกล้เป็นศูนย์ แทนที่จะยิงรัวๆ จนโดนบล็อก เพราะขีดจำกัดที่แท้จริงอาจต่างกันไปตามประเภท token หรือ endpoint จึงไม่ควรฝังตัวเลขคงที่ไว้ในโค้ด แต่ให้ตรวจจาก header สดทุกครั้งแทน ตัวอย่างการอ่าน header ด้วย curl curl -I -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" "https://api.digitalocean.com/v2/droplets" คำสั่งนี้ใช้ -I เพื่อดูเฉพาะ header โดยไม่ต้องโหลด body เต็ม เหมาะกับการเช็คโควตาแบบเบาๆ ก่อนยิง request จริง เมื่อโควตาหมดจริงๆ API จะตอบกลับด้วย HTTP status 429 Too Many Requests ซึ่งสคริปต์ควรจับ status นี้แล้วหน่วงเวลาก่อนลองใหม่ (retry) แทนที่จะยิงซ้ำทันที รูปแบบที่นิยมคือ exponential backoff คือรอเพิ่มขึ้นเป็นเท่าตัวทุกครั้งที่ retry ล้มเหลว เช่น รอ 1 วินาที, 2 วินาที, 4 วินาที ไปเรื่อยๆ จนถึงเพดานที่กำหนด ส่วน error อื่นที่พบได้ทั่วไปคือ 401 Unauthorized (token ผิดหรือหมดอายุ), 404 Not Found (id ของ resource ไม่มีอยู่จริงหรือพิมพ์ผิด), 422 Unprocessable Entity (ส่ง field ผิดรูปแบบ เช่น size slug ที่ไม่มีอยู่จริง) และ 500/503 (ปัญหาฝั่งเซิร์ฟเวอร์ ควร retry ได้) ทุก error response จะมี JSON body รูปแบบเดียวกันคือ {"id": "not_found", "message": "The resource you were accessing could not be found."} ซึ่งสคริปต์ควร parse field message ออกมา log ไว้เสมอ แทนการแสดงแค่ HTTP status code เฉยๆ เพราะข้อความอธิบายมักบอกสาเหตุที่ชัดเจนกว่า เช่น field ไหนที่ส่งผิด ทำให้ debug ได้เร็วกว่ามาก โดยเฉพาะเวลาเขียนสคริปต์ที่รันแบบ unattended บน cron หรือ CI ที่ไม่มีคนนั่งดู log สดๆ การ log message error แบบเต็มจึงสำคัญกว่าปกติ
- ตรวจโควตาจาก HTTP header RateLimit-Limit / RateLimit-Remaining / RateLimit-Reset ทุก response แทนการฝังตัวเลขคงที่ในโค้ด
- โควตาหมดจะได้ HTTP 429 Too Many Requests ควร retry แบบ exponential backoff
- 401 = token ผิด/หมดอายุ, 404 = id ไม่พบ, 422 = field ข้อมูลผิดรูปแบบ
ใช้ API ร่วมกับ script อัตโนมัติ
เมื่อเข้าใจ endpoint หลักและวิธีจัดการ error แล้ว ขั้นตอนถัดไปคือรวมทุกอย่างเป็นสคริปต์ที่รันซ้ำได้โดยไม่ต้องมีคนคอยกดเอง ตัวอย่างง่ายที่สุดคือสคริปต์ bash ที่ใช้ curl ร่วมกับ jq (เครื่องมือ parse JSON บน command line) เพื่อสร้าง Droplet แล้วรอจนสถานะพร้อมใช้งานก่อนพิมพ์ IP ออกมา DROPLET_ID=$(curl -s -X POST -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" -H "Content-Type: application/json" -d '{"name":"web-01","region":"sgp1","size":"s-1vcpu-1gb","image":"ubuntu-24-04-x64"}' "https://api.digitalocean.com/v2/droplets" | jq -r '.droplet.id') จากนั้นวน loop เช็คสถานะด้วย while ร่วมกับ GET /v2/droplets/$DROPLET_ID จนกว่า field status จะเป็น active แล้วค่อยดึง IP ออกมาด้วย jq จาก .droplet.networks.v4[0].ip_address เพื่อนำไปใช้ในขั้นตอนถัดไป เช่น เพิ่ม record DNS ให้ชี้มาที่ IP นี้ทันทีแบบอัตโนมัติ สำหรับงานที่ต้องรันตามตารางเวลา เช่น สำรองข้อมูลทุกคืน สามารถใช้ cron เรียกสคริปต์ที่สร้าง Snapshot แล้วลบ Snapshot เก่าตามที่กล่าวในหัวข้อก่อนหน้าได้เลย โดยตั้ง crontab เช่น 0 3 * * * /home/user/scripts/do-backup.sh ให้รันทุกตี 3 ถ้าทีมใช้ Python อยู่แล้ว ก็เขียนด้วย library requests แทน curl ได้ในลักษณะเดียวกัน หรือจะใช้ library ทางการ pydo ที่ห่อ endpoint ต่างๆ ไว้เป็นฟังก์ชันสำเร็จรูปก็ได้ ลดโอกาสพิมพ์ URL หรือ field ผิด อีกทางเลือกหนึ่งที่ไม่ต้องเขียน curl เองเลยคือใช้ doctl ซึ่งเป็น CLI ทางการของ DigitalOcean ที่ห่อ API v2 ไว้แล้ว ติดตั้งผ่าน brew บน macOS หรือ snap บน Linux จากนั้น auth ด้วย doctl auth init พร้อม Personal Access Token ตัวเดียวกับที่สร้างไว้ก่อนหน้านี้ คำสั่งอย่าง doctl compute droplet create web-01 --region sgp1 --size s-1vcpu-1gb --image ubuntu-24-04-x64 ก็ทำงานเดียวกับตัวอย่าง curl ด้านบนแต่สั้นกว่ามาก เหมาะกับใช้ในสคริปต์ที่เน้นความอ่านง่าย สำหรับระบบ CI/CD เช่น GitHub Actions สามารถเก็บ token ไว้เป็น encrypted secret ของ repository แล้วอ้างอิงในไฟล์ workflow ผ่าน ${{ secrets.DIGITALOCEAN_TOKEN }} เพื่อให้ pipeline เรียก API หรือ doctl ได้โดยไม่ต้องเปิดเผยค่า token ในโค้ดหรือ log เลย ทำให้ขั้นตอน provision หรือ deploy กลายเป็นส่วนหนึ่งของ pipeline อัตโนมัติเต็มรูปแบบ ไม่ต้องมีใครมานั่งรันคำสั่งเองทีละขั้นตอนอีกต่อไป
- รวม curl + jq เป็นสคริปต์ bash สร้าง Droplet แล้ว poll สถานะจนถึง active ก่อนดึง IP ไปใช้ต่อ
- ตั้ง cron job เรียกสคริปต์ snapshot/backup ตามตารางเวลาที่ต้องการ
- ใช้ Python requests หรือ library ทางการ pydo แทน curl ได้ในลักษณะเดียวกัน
- doctl (CLI ทางการ) ห่อ API ไว้แล้ว คำสั่งสั้นกว่าการเขียน curl เอง เหมาะกับสคริปต์ที่เน้นอ่านง่าย
- เก็บ token เป็น encrypted secret ใน CI/CD (เช่น GitHub Actions) เพื่อ automate การ provision/deploy เต็มรูปแบบ
ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข
จุดที่ผู้ใช้มักถามมาคือ เมื่อใช้งาน API v2 จริงในสคริปต์ที่รันซ้ำๆ หรือเชื่อมกับระบบอื่น มักเจอข้อผิดพลาดซ้ำๆ กันไม่กี่แบบ ที่พบบ่อยที่สุดคือการจัดการ 401 Unauthorized ผิดวิธี หลายทีมเขียนสคริปต์ให้ crash ทันทีเมื่อเจอ 401 โดยไม่แยกแยะว่าสาเหตุคือ token หมดอายุจริง หรือแค่ environment variable โหลดไม่ถูกต้อง เช่น deploy ไปเครื่องใหม่แล้วลืมตั้งค่า secret วิธีที่ดีกว่าคือ log ค่า response body เต็มจาก error (ที่มี field message อธิบายสาเหตุ) แทนการดักจับแค่ status code เฉยๆ เพื่อให้แยกได้ว่าเป็นปัญหาที่ต้อง rotate token ใหม่ หรือแค่ config ผิดที่แก้ได้ทันที อีกจุดที่พลาดบ่อยคือการจัดการ 422 Unprocessable Entity error นี้มักเกิดจากส่ง field ผิดรูปแบบ เช่นพิมพ์ size slug ผิด (เช่น s-1vcpu-1g แทนที่จะเป็น s-1vcpu-1gb) หรือส่ง region ที่ไม่มีอยู่จริง จุดที่พลาดคือสคริปต์จำนวนมาก retry request เดิมซ้ำๆ เมื่อเจอ 422 ทั้งที่ 422 คือปัญหาที่ข้อมูล request เอง ไม่ใช่ปัญหาชั่วคราวแบบ 429 หรือ 503 การ retry แบบเดิมซ้ำจะไม่มีทางสำเร็จและเสียเวลาโดยเปล่าประโยชน์ ควรแยก error ที่ retry ได้ (429, 500, 503) ออกจาก error ที่ retry ไม่ได้ (400, 401, 404, 422) อย่างชัดเจนในโค้ด แล้วให้ error กลุ่มหลัง fail ทันทีพร้อม log รายละเอียดแทนการวนซ้ำ ปัญหาที่เจอบ่อยอีกอย่างคือ pagination bug สคริปต์ที่ดึงรายการ Droplet หรือ record จำนวนมากบางตัวลืมเช็ค links.pages.next ในทุกหน้า ทำให้ดึงข้อมูลได้แค่หน้าแรกตามค่า per_page เริ่มต้น แล้วเข้าใจผิดว่าครบแล้ว วิธีแก้คือวน loop ตาม links.pages.next จนกว่าจะไม่มี key นี้อีก หรือระบุ per_page สูงขึ้นตั้งแต่แรกในสคริปต์ที่รู้ว่าจำนวนรายการเยอะแน่ๆ เช่น curl -X GET -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" "https://api.digitalocean.com/v2/droplets?per_page=200" สุดท้ายคือปัญหา idempotency endpoint สร้าง resource อย่าง POST /v2/droplets ไม่มีกลไก idempotency key ในตัว ถ้าสคริปต์ยิง POST ซ้ำเพราะ network timeout หรือ retry โดยไม่เช็คก่อน อาจได้ Droplet ซ้ำสองตัวโดยไม่ได้ตั้งใจ ทางแก้คือก่อน retry การสร้าง resource ควร GET เช็คก่อนว่ามีอยู่แล้วหรือยัง เช่นเช็คจากชื่อที่ตั้งไว้ หรือใส่ logic กันซ้ำในระดับแอปเอง และที่อันตรายกว่านั้นคือ retry-storm บน 429 ถ้าสคริปต์หลายตัวพร้อมกันเจอ 429 แล้ว retry ทันทีโดยไม่มี backoff หรือ jitter เลย จะยิ่งซ้ำเติมปัญหาโควตาให้แย่ลงไปอีก ควรใส่ delay แบบสุ่ม (jitter) เพิ่มเข้าไปในการหน่วงเวลาแต่ละครั้งด้วย ไม่ใช่แค่ fixed interval เดียวกันทุกตัว เพื่อกระจายการ retry ไม่ให้ชนกันเป็นชุด
- แยก error ที่ retry ได้ (429/500/503) ออกจาก error ที่ retry ไม่ได้ (401/404/422) อย่างชัดเจน อย่า retry request ที่ผิดตั้งแต่ต้น
- log response body เต็ม (field message) เมื่อเจอ 401 แทนการเดาสาเหตุจาก status code อย่างเดียว
- เช็ค links.pages.next ทุกหน้าเวลาดึง list ขนาดใหญ่ หรือเพิ่ม per_page ตั้งแต่แรก ป้องกัน pagination bug
- เช็คว่า resource มีอยู่แล้วก่อน retry การสร้างใหม่ ป้องกัน Droplet/record ซ้ำจากปัญหา idempotency
- เพิ่ม jitter (delay สุ่ม) ในการ retry ไม่ใช่แค่ fixed interval ป้องกัน retry-storm ตอนโดน 429 พร้อมกันหลายสคริปต์
แนวทางปฏิบัติที่ดีที่สุด (Best Practices)
เมื่อใช้ API v2 ในระบบที่รันจริงระยะยาว มีแนวทางที่ช่วยลดปัญหาและความเสี่ยงได้อย่างเป็นรูปธรรม เริ่มจากเรื่อง token scoping ควรสร้าง token แยกตามหน้าที่งานแทนการใช้ token เดียวกันทั้งระบบ เช่น token สำหรับสคริปต์ backup ให้ตั้ง scope เท่าที่จำเป็น ไม่ต้องมีสิทธิ์ลบ Droplet ถ้างานนั้นไม่ได้ทำอะไรกับ Droplet เลย การแยก scope แบบนี้ทำให้ถ้า token ตัวใดตัวหนึ่งหลุดออกไป ความเสียหายจะจำกัดอยู่แค่ขอบเขตของ token นั้น ไม่กระทบทั้งบัญชี ควบคู่กับการทำ token rotation เป็นระยะ เช่น สร้าง token ใหม่ทุก 90 วันแล้ว revoke ตัวเก่า แทนการใช้ token เดิมค้างไว้นานเป็นปีโดยไม่เปลี่ยน เรื่องถัดมาคือ webhook verification สำหรับระบบที่ตั้งค่าให้มีการยิง callback กลับมาที่ endpoint ของตัวเองเมื่อมีเหตุการณ์เกิดขึ้น เช่นระบบ monitoring ภายนอกที่เชื่อมกับ Alert Policy ปลายทางที่รับ webhook ต้องตรวจสอบแหล่งที่มาของ request ก่อนเชื่อถือข้อมูลเสมอ เช่น เช็ค IP ต้นทางหรือ signature header ที่ระบบต้นทางแนบมา ไม่ควรเชื่อ payload ที่ส่งเข้ามาโดยไม่มีการยืนยันตัวตนใดๆ เลย เพราะ endpoint ที่เปิดรับ webhook แบบไม่มีการตรวจสอบเป็นช่องทางที่มักถูกโจมตีด้วยการปลอม request ด้าน retry logic ควรใช้ exponential backoff ร่วมกับ jitter เป็นมาตรฐานเดียวกันทั้งระบบ ไม่ใช่เขียนแยกกันในแต่ละสคริปต์ เช่นเขียนเป็นฟังก์ชันกลางที่ทุกสคริปต์เรียกใช้ร่วมกัน retry_with_backoff() { local attempt=0; local max=5; until curl -sf -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" "$1"; do attempt=$((attempt+1)); [ $attempt -ge $max ] && return 1; sleep $((2**attempt)); done; } ฟังก์ชันลักษณะนี้ช่วยให้ทุกจุดที่เรียก API ในระบบมีพฤติกรรม retry ที่สอดคล้องกัน ไม่ต้องแก้หลายที่เวลาต้องปรับ สุดท้ายคือเรื่อง logging และ observability สคริปต์ automation ที่รันแบบ unattended บน cron หรือ CI ควร log ทุกครั้งที่เรียก API อย่างน้อยต้องมี timestamp, endpoint ที่เรียก, HTTP status ที่ได้กลับมา และ id ของ resource ที่เกี่ยวข้อง เช่น droplet id เก็บไว้เป็นไฟล์ log แยกต่างหาก ไม่ใช่แค่พิมพ์ออกหน้าจอเฉยๆ เพราะเมื่อเกิดปัญหาย้อนหลัง เช่น Droplet หายไปโดยไม่รู้สาเหตุ หรือ Snapshot ไม่ถูกสร้างตามตารางเวลา จะได้มี log ย้อนกลับไปดูว่าสคริปต์เรียก API อะไรไปบ้างในช่วงเวลานั้น แทนการเดาสุ่มว่าเกิดอะไรขึ้น ทีมที่มีสคริปต์ automation หลายตัวทำงานร่วมกันควรพิจารณาส่ง log เหล่านี้เข้าระบบรวมศูนย์ (centralized logging) ด้วย เพื่อให้ตรวจสอบเหตุการณ์ข้ามสคริปต์ได้ง่ายขึ้น
- แยก token ตามหน้าที่งาน ตั้ง scope เท่าที่จำเป็นต่อสคริปต์นั้นๆ จำกัดความเสียหายถ้า token หลุด
- ทำ token rotation เป็นระยะ (เช่นทุก 90 วัน) แทนใช้ token เดิมค้างไว้นานโดยไม่เปลี่ยน
- ตรวจสอบแหล่งที่มาของ webhook/callback ก่อนเชื่อถือข้อมูลเสมอ ไม่เปิดรับ payload โดยไม่มีการยืนยันตัวตน
- ใช้ exponential backoff + jitter เป็นฟังก์ชันกลางเดียวที่ทุกสคริปต์เรียกใช้ร่วมกัน แทนเขียนแยกแต่ละที่