← กลับไปหน้าบทความ
คู่มือ

เขียน Webhook ด้วย Supabase Edge Functions หรือ Next.js API Route ต่างกันตรงไหน

ทีมบรรณาธิการ linli12 ส.ค. 04:52อัปเดต 12 ส.ค. 04:52อ่าน 5 นาที
เขียน Webhook ด้วย Supabase Edge Functions หรือ Next.js API Route ต่างกันตรงไหน
บทความนี้จัดทำเพื่อความรู้ ชื่อธุรกิจ ตัวเลข หรือบทสนทนาที่ไม่มีแหล่งอ้างอิงกำกับเป็นกรณีตัวอย่างเพื่ออธิบายแนวคิด ดูรายละเอียดที่ นโยบายกองบรรณาธิการ

สรุปสั้น ๆ

Supabase Edge Functions คือฟังก์ชัน serverless ที่รันบน Deno runtime กระจายอยู่ตามจุด edge ทั่วโลก เหมาะกับงานที่ต้องอยู่ใกล้ฐานข้อมูล Supabase ต้องซ่อน secret key หรือรับ Webhook จากภายนอก ส่วน API Route ของเฟรมเวิร์กอย่าง Next.js รันบน Node runtime และผูกอยู่กับ deployment ของแอปนั้นโดยตรง เลือกผิดจุดจะเจอปัญหาเรื่อง cold start และ dependency ไม่ตรงกัน

มีคำถามหนึ่งที่ทีมพัฒนาที่ใช้ Supabase มักเจอตอนต้องเขียนโค้ดฝั่งเซิร์ฟเวอร์สักชิ้น คือ ควรใส่ logic นั้นไว้ใน Edge Functions ของ Supabase เอง หรือใส่ไว้ใน API Route ของเฟรมเวิร์กที่ใช้อยู่แล้วอย่าง Next.js, Nuxt หรือ SvelteKit ดี ทั้งสองทางเขียนด้วย TypeScript เหมือนกัน รับ HTTP request ได้เหมือนกัน หน้าตาโค้ดคล้ายกันจนหลายคนมองว่าเลือกทางไหนก็ได้ ไม่ต่างกัน

แต่พอเอาเข้างานจริง โดยเฉพาะงานที่ต้องรับ Webhook จากภายนอก ต้องเรียก AI Model ต่อ หรือต้องทำงานที่แตะฐานข้อมูลบ่อยและเร็ว ความต่างของ runtime และตำแหน่งที่รันจะเริ่มส่งผลชัดเจน บางทีมเลือกผิดทางแล้วมาเจอปัญหาทีหลัง เช่น cold start ที่ทำให้ Webhook timeout หรือ package บางตัวใช้ไม่ได้เพราะ runtime ไม่รองรับ

บทความนี้จะไม่บอกว่าทางไหน 'ดีกว่า' เพราะมันไม่มีคำตอบเดียว แต่จะแยกให้เห็นว่าโครงสร้างของทั้งสองต่างกันตรงไหน แล้วงานลักษณะไหนควรอยู่ที่ไหน เพื่อให้ตัดสินใจได้เร็วขึ้นตั้งแต่ตอนออกแบบระบบ ไม่ต้องมาย้ายทีหลัง

Supabase Edge Functions คืออะไร ทำงานยังไงจริง ๆ

Edge Functions เป็นฟังก์ชัน serverless ที่ Supabase รันให้บน Deno runtime แทนที่จะเป็น Node.js แบบที่คุ้นเคยกัน แต่ละฟังก์ชันคือไฟล์ TypeScript หนึ่งไฟล์ (หรือหลายไฟล์ในโฟลเดอร์เดียว) ที่ export default handler รับ Request แล้วคืน Response ตามมาตรฐาน Web API เหมือนที่ใช้ใน browser ไม่ใช่ API สไตล์ Express ที่นักพัฒนา Node คุ้นเคย

จุดที่ทำให้มันถูกเรียกว่า 'Edge' ไม่ใช่แค่ชื่อทางการตลาด แต่เพราะ Supabase deploy โค้ดชุดเดียวกันไปกระจายตามจุดต่าง ๆ ทั่วโลก แล้วให้ผู้ใช้แต่ละคนยิง request เข้าจุดที่อยู่ใกล้ที่สุด ลด latency ของเครือข่ายลง ต่างจาก server แบบเดิมที่ตั้งอยู่ที่เดียวแล้วทุกคนต้องวิ่งเข้ามาหาจุดนั้น

อีกจุดสำคัญคือ Edge Functions รันอยู่ใกล้กับ Postgres database ของโปรเจกต์ Supabase เดียวกัน (แม้จะไม่ได้อยู่เครื่องเดียวกันเป๊ะ) ทำให้การเรียก query ผ่าน service role key หรือผ่าน connection pooler มัก latency ต่ำกว่าการยิงจาก server ภายนอกที่ตั้งอยู่คนละ region กับฐานข้อมูล

ต่างจาก API Route ของเฟรมเวิร์กตรงไหนบ้าง

ความต่างข้อแรกคือ runtime เอง Edge Functions ใช้ Deno ซึ่งรองรับ ES Module และ Web API มาตรฐานเป็นหลัก npm package บางตัวที่พึ่งพา Node API เฉพาะทาง เช่นการเข้าถึง filesystem แบบตรง ๆ หรือ native binding บางชนิด อาจใช้ไม่ได้เลยหรือใช้ได้แบบมีเงื่อนไข ต้องเช็คความเข้ากันได้ก่อนทุกครั้งที่จะพึ่งพา library ภายนอก

ความต่างข้อสองคือวงจรชีวิตของ deployment API Route ของ Next.js ผูกอยู่กับการ deploy แอปทั้งก้อน ทุกครั้งที่ deploy แอปใหม่ API Route ก็ถูก deploy ตามไปด้วยโดยอัตโนมัติ ส่วน Edge Functions ของ Supabase deploy แยกเป็นเอกเทศผ่านคำสั่งของตัวเอง ทำให้แก้ logic ฝั่งฟังก์ชันได้โดยไม่ต้อง build หรือ deploy แอป frontend ใหม่ทั้งก้อน ซึ่งมีประโยชน์มากเวลาต้องแก้ Webhook handler แบบเร่งด่วน

ความต่างข้อสามคือเรื่อง cold start ทั้งสองทางมี cold start ได้ทั้งคู่เพราะเป็นสถาปัตยกรรม serverless เหมือนกัน แต่ลักษณะ workload ต่างกัน ถ้า API Route ของแอปมี traffic สม่ำเสมออยู่แล้วจาก request ปกติของผู้ใช้ instance มักถูก warm ไว้บ่อยกว่า ขณะที่ Edge Functions ที่ใช้เฉพาะรับ Webhook นาน ๆ ครั้งอาจเจอ cold start บ่อยกว่า ควรทดสอบ latency จริงของงานตัวเองก่อนตัดสินว่ารับได้ไหม

งานแบบไหนที่เหมาะกับ Edge Functions จริง ๆ

จากประสบการณ์ใช้งานจริง มีสามกลุ่มงานที่ Edge Functions ทำได้ดีกว่าการยัดไว้ใน API Route ของแอป frontend

  • รับ Webhook จากบริการภายนอก — เช่น payment gateway, ระบบส่งอีเมล หรือบริการ AI ที่ทำงานแบบ async แล้วยิงกลับมาแจ้งผล การแยก endpoint ไว้ที่ Edge Functions ทำให้ไม่ต้อง deploy แอปหลักใหม่ทุกครั้งที่ปรับ logic รับ Webhook
  • ซ่อน secret key ที่ห้ามหลุดไปฝั่ง client — เช่น API key ของบริการ AI ราคาแพงต่อ token การเรียกผ่าน Edge Functions ทำให้ secret อยู่ในตัวแปรแวดล้อมฝั่งเซิร์ฟเวอร์เท่านั้น ไม่มีทางรั่วไปกับ JavaScript bundle ฝั่งหน้าเว็บ
  • ทำงานที่ต้องใช้ service role key เข้าถึงข้อมูลข้าม RLS — เช่น สร้างรายงานสรุปข้ามผู้ใช้ทุกคน หรือ migrate ข้อมูลบางส่วน งานลักษณะนี้ต้องข้าม Row Level Security ที่อธิบายไว้ในบทความเรื่อง Supabase RLS คืออะไร ซึ่งควรทำในฝั่งเซิร์ฟเวอร์ที่ควบคุมได้เท่านั้น ไม่ควรทำในฝั่ง client แม้แต่ตอน prototype
  • ต่อ AI Model จากภายนอก — เพราะ Edge Functions รองรับ streaming response ได้ตามมาตรฐาน Web API ทำให้ต่อกับ AI Workflow ที่ต้อง stream คำตอบทีละ token ได้สะดวก อ่านรายละเอียดเพิ่มได้ในบทความ ใช้ Edge Functions เรียก AI Model

งานแบบไหนที่ยังไม่ควรยัดใส่ Edge Functions

ไม่ใช่ทุกงานฝั่งเซิร์ฟเวอร์ที่ควรอยู่ใน Edge Functions บางเคสใส่ไว้ใน API Route ของแอปหลักเลยยังเหมาะกว่า

งานที่ต้อง render หน้าเว็บแบบ server-side ผูกกับ routing ของแอปโดยตรง เช่น การดึงข้อมูลมา render หน้า product page ควรอยู่ใน server component หรือ API Route ของเฟรมเวิร์กเพราะมันผูกกับ lifecycle ของหน้าเว็บอยู่แล้ว การแยกไปเรียก Edge Functions เพิ่มอีกชั้นมีแต่จะเพิ่ม latency โดยไม่ได้ประโยชน์อะไร

งานที่ต้องใช้ npm package เฉพาะทางที่พึ่งพา Node runtime หนัก ๆ เช่น library ประมวลผลภาพหรือไฟล์ PDF บางตัวที่ compile เป็น native binary ถ้า package นั้นไม่มีเวอร์ชันที่รองรับ Deno ให้พิจารณาทำงานนั้นในฝั่ง backend แบบ Node แยกต่างหาก แล้วให้ Edge Functions เป็นแค่ตัวกลางเรียกต่อแทน

งานที่ต้องรันนานเกินขีดจำกัดเวลาของ Edge Functions เช่น process ข้อมูลก้อนใหญ่เป็นนาที ควรแยกไปทำใน background job หรือ queue แทน อย่าฝืนยัดใส่ฟังก์ชันแบบ synchronous เพราะ request จะ timeout ก่อนงานเสร็จ

ตัวอย่างสมมติ: สร้าง Webhook รับ event จากระบบชำระเงิน

เพื่อให้เห็นภาพชัดขึ้น ลองดูขั้นตอนคร่าว ๆ ของการสร้าง Edge Function รับ Webhook จากบริการชำระเงินภายนอกสักตัวหนึ่ง (ตัวอย่างสมมติ เพื่อประกอบการอธิบายเท่านั้น ไม่ใช่ข้อมูลจากระบบจริง):

  1. สร้างฟังก์ชันใหม่ด้วยคำสั่ง CLI เช่น 'supabase functions new payment-webhook' ซึ่งจะได้โฟลเดอร์พร้อมไฟล์ index.ts ตั้งต้นให้
  2. ตรวจสอบลายเซ็นของ request ที่ส่งมาก่อนเสมอ (signature verification) เพื่อยืนยันว่า request มาจากผู้ให้บริการจริง ไม่ใช่ใครก็ได้ยิงมาสวมรอย ขั้นตอนนี้ห้ามข้ามแม้จะเร่งเวลา
  3. หลังยืนยันแล้ว ให้เขียนข้อมูล event ลงตาราง Postgres ผ่าน service role key เช่นบันทึกสถานะการชำระเงินเป็น 'paid' และผูกกับ order_id ที่เกี่ยวข้อง
  4. คืน HTTP 200 กลับไปให้เร็วที่สุดหลังบันทึกสำเร็จ เพราะผู้ให้บริการภายนอกส่วนใหญ่จะ retry ถ้าไม่ได้รับ response ภายในเวลาที่กำหนด การประมวลผลที่หนักควรแยกไปทำต่อแบบ async แทนที่จะทำให้ก่อนตอบกลับ
  5. เขียน log หรือเก็บ raw payload ไว้ชั่วคราวด้วย เผื่อวันหนึ่งต้อง debug ย้อนหลังว่าทำไม event บางตัวไม่ถูกประมวลผล

Deploy และจัดการ secret ให้ปลอดภัย

การ deploy Edge Functions ทำผ่าน Supabase CLI ด้วยคำสั่งประมาณ 'supabase functions deploy <ชื่อฟังก์ชัน>' ซึ่งอัปโหลดเฉพาะฟังก์ชันนั้นขึ้นไปโดยไม่กระทบฟังก์ชันอื่นหรือแอปหลัก ทำให้ปรับแก้ Webhook handler ได้บ่อยโดยไม่ต้องผ่านขั้นตอน CI/CD ทั้งชุดของแอป frontend

ตัวแปรแวดล้อมอย่าง API key ของบริการภายนอกไม่ควรฝังในโค้ดตรง ๆ ให้ใช้คำสั่ง 'supabase secrets set' ตั้งค่าไว้ในระดับโปรเจกต์แทน แล้วอ่านค่าผ่าน Deno.env.get() ในฟังก์ชัน วิธีนี้ทำให้ secret ไม่ถูก commit เข้า git repository โดยไม่ตั้งใจ

อีกจุดที่พลาดกันบ่อยคือใช้ service role key ในฟังก์ชันที่เปิดให้เรียกจากฝั่ง client ได้โดยตรง เพราะ service role key ข้าม RLS ทุกกฎ ถ้าฟังก์ชันนั้นไม่มีการตรวจสอบสิทธิ์เพิ่มเติมเอง ใครก็ยิง request มาดึงข้อมูลของคนอื่นได้หมด ควรใช้ service role key เฉพาะในฟังก์ชันที่มี logic ตรวจสอบสิทธิ์ของตัวเองอย่างรัดกุมเท่านั้น

ตารางเทียบ Edge Functions กับทางเลือกอื่นแบบเห็นภาพ

เพื่อสรุปให้ตัดสินใจง่ายขึ้น นี่คือตารางเทียบสามทางเลือกที่มักถูกเอามาเทียบกันเวลาต้องเขียนโค้ดฝั่งเซิร์ฟเวอร์กับ Supabase:

ประเด็นSupabase Edge FunctionsAPI Route ของเฟรมเวิร์กPostgres Function (plpgsql)
RuntimeDenoNode (ส่วนใหญ่)รันในตัวฐานข้อมูลเอง
Deploy แยกจากแอปหลักไหมแยกได้ผูกกับ deploy แอปแยกผ่าน migration
เหมาะกับ Webhook ภายนอกเหมาะมากทำได้ไม่เหมาะ ไม่มี HTTP endpoint ตรง
latency ถึง Postgresต่ำ (อยู่ใกล้ DB)ขึ้นกับ region ของ deployต่ำที่สุด (รันในตัว DB)
เหมาะกับ logic ซับซ้อนข้าม serviceเหมาะเหมาะไม่เหมาะ ยากต่อการ maintain

ทำแบบนี้แล้วพัง เพราะอะไร

มีข้อผิดพลาดบางแบบที่ทีมที่เริ่มใช้ Edge Functions ครั้งแรกมักเจอซ้ำ ๆ เพราะความเคยชินจาก Node runtime

  • ลืมว่า Deno ไม่ใช่ Node — import package แบบ CommonJS ตรง ๆ แล้วรันไม่ผ่าน ต้องเช็คว่า package รองรับ ES Module หรือมี build เฉพาะสำหรับ Deno/edge runtime ก่อนเสมอ
  • ไม่ตรวจสอบลายเซ็นของ Webhook — เปิด endpoint รับ event โดยไม่ตรวจว่ามาจากผู้ให้บริการจริง ทำให้ใครก็ยิง fake event เข้ามาปลอมสถานะการชำระเงินได้
  • ทำงานหนักก่อนตอบ response — ประมวลผลข้อมูลใหญ่ก่อนคืน HTTP 200 ทำให้ผู้ส่ง Webhook คิดว่า timeout แล้ว retry ซ้ำ สุดท้ายข้อมูลถูกบันทึกซ้อนกันหลายรอบ
  • ใช้ service role key แบบไม่มีการตรวจสิทธิ์เพิ่ม — เปิดฟังก์ชันให้ client เรียกตรงได้พร้อม service role key ฝังอยู่ ทำให้ทุกคนที่รู้ URL ดึงข้อมูลข้าม RLS ได้ทั้งระบบ

สรุป

คำถามที่ถูกต้องไม่ใช่ 'Edge Functions ดีกว่า API Route ไหม' แต่คือ 'งานชิ้นนี้ต้องการอะไรจากที่ที่มันรัน' ถ้าเป็นงานที่ต้องซ่อน secret ต้องอยู่ใกล้ฐานข้อมูล หรือต้อง deploy แยกจากแอปหลักได้ Edge Functions มักตอบโจทย์กว่า ส่วนงานที่ผูกกับ routing และ lifecycle ของหน้าเว็บอยู่แล้ว การใส่ไว้ใน API Route ของเฟรมเวิร์กยังเป็นทางที่ตรงไปตรงมากว่า

สิ่งสำคัญคือทดสอบให้แน่ใจตั้งแต่ช่วง prototype ว่า package และ logic ที่จะใช้รันได้จริงบน Deno runtime ก่อนออกแบบสถาปัตยกรรมทั้งระบบตามมัน เพราะการย้ายจาก Node ไป Deno หรือกลับกันทีหลังมักเสียเวลามากกว่าคิดให้ถูกตั้งแต่ต้น

  • Edge Functions รันบน Deno กระจายตาม edge ทั่วโลก เหมาะกับ Webhook, secret key, และงานที่ต้องอยู่ใกล้ Postgres
  • API Route ของเฟรมเวิร์กยังเหมาะกับ logic ที่ผูกกับ routing ของหน้าเว็บโดยตรง
  • ตรวจลายเซ็น Webhook ทุกครั้ง และอย่าฝัง service role key ในฟังก์ชันที่ client เรียกตรงได้โดยไม่มีการตรวจสิทธิ์

คำถามที่พบบ่อย

Edge Functions ต่างจาก Database Function (plpgsql) ยังไง

Database Function รันอยู่ในตัว Postgres โดยตรง เหมาะกับ logic ที่ทำงานกับข้อมูลล้วน ๆ และไม่ต้องเรียก API ภายนอก ส่วน Edge Functions รันแยกเป็น process ต่างหาก เหมาะกับงานที่ต้องเรียก HTTP ออกไปหาบริการอื่น เช่น Webhook หรือ AI API

เขียน Edge Functions ด้วย npm package ทั่วไปได้ไหม

ได้บางส่วน ขึ้นอยู่กับว่า package นั้นรองรับ ES Module และไม่พึ่งพา Node API เฉพาะทาง ควรทดสอบ import จริงก่อนวางแผนพึ่งพา library ตัวไหนเป็นหลัก

Edge Functions มีข้อจำกัดเรื่องเวลาทำงานไหม

มี ฟังก์ชันแบบ serverless ทุกเจ้ามีเพดานเวลาทำงานต่อ request ถ้างานที่ต้องทำใช้เวลานานกว่านั้น ควรแยกไปทำแบบ background job หรือ queue แทนการรอใน request เดียว

ควรทดสอบ Edge Functions ในเครื่องตัวเองได้ไหมก่อน deploy จริง

ได้ Supabase CLI มีคำสั่งรันฟังก์ชันแบบ local ผ่าน Docker ทำให้ทดสอบ logic และตัวแปรแวดล้อมก่อน deploy ขึ้นจริงได้ ช่วยลดความเสี่ยงที่จะพัง production

ถ้า Webhook ยิงเข้ามาถี่มากพร้อมกัน Edge Functions รับไหวไหม

โดยพื้นฐานรองรับ concurrent request ได้ในระดับหนึ่งเพราะเป็นสถาปัตยกรรม serverless แต่ถ้าทุก request ต้องเขียนลงตารางเดียวกันพร้อมกันจำนวนมาก ควรออกแบบ schema และ index ให้รองรับการเขียนพร้อมกันด้วย ไม่ใช่พึ่งแค่ตัวฟังก์ชันอย่างเดียว

จำเป็นต้องใช้ Edge Functions ทุกโปรเจกต์ไหม

ไม่จำเป็น โปรเจกต์เล็กที่ไม่มี Webhook ภายนอกหรือไม่ต้องซ่อน secret key พิเศษ อาจใช้ API Route ของเฟรมเวิร์กที่ใช้อยู่แล้วได้เพียงพอโดยไม่ต้องเพิ่มความซับซ้อนของระบบ

ลองตรวจด้วยตัวเอง

LINE Webhook Payload Inspector

วาง JSON payload จาก LINE แล้วดูว่าเป็น event ชนิดไหน มี field ครบตาม schema ปัจจุบันหรือไม่

ตรวจ payload ฟรี

ใช้ฟรี ไม่ต้องสมัคร ไม่เก็บข้อมูลที่คุณกรอก

ทดลองวัดผลโฆษณาเข้า LINE ฟรี 14 วัน

สมัครแล้วสร้างโปรเจกต์ เชื่อม LINE ติดตั้ง Tracking แล้วเริ่มเห็น Funnel จาก Click ถึง Purchase ได้ทันที ไม่ต้องใช้บัตรเครดิต

เริ่มทดลองใช้ฟรี 14 วัน

บทความที่เกี่ยวข้อง

บอทมี RAG ครบแล้ว ทำไมบางคำถามยังตอบผิดหรือตอบไม่ได้เลย

บอทมี RAG ครบแล้ว ทำไมบางคำถามยังตอบผิดหรือตอบไม่ได้เลย

ทีมที่ต่อโมเดลภาษาเข้ากับฐานข้อมูลแล้วยังเจอปัญหาบอทตอบผิดหรือตอบไม่ได้บ่อย ทั้งที่คำตอบที่ถูกต้องมีอยู่ในเอกสารจริง บทความนี้อธิบายว่า Supabase RAG ควรออกแบบฐานข้อมูล ขั้นตอนดึงข้อมูล และการวัดคุณภาพยังไง เพื่อลดปัญหาคำตอบผิดพลาด
ไฟล์ที่อัปโหลดขึ้น Supabase Storage ไม่ได้ปลอดภัยอัตโนมัติ ต้องผูก RLS เอง

ไฟล์ที่อัปโหลดขึ้น Supabase Storage ไม่ได้ปลอดภัยอัตโนมัติ ต้องผูก RLS เอง

หลายทีมเข้าใจผิดว่าอัปโหลดไฟล์ขึ้น Supabase Storage แล้วปลอดภัยเองโดยอัตโนมัติ แต่จริง ๆ ต้องตั้ง policy ควบคุมสิทธิ์เหมือนตารางในฐานข้อมูล บทความนี้อธิบายว่า Storage ทำงานยังไงและควบคุมสิทธิ์ร่วมกับ RLS แบบไหน
Supabase Auth คืออะไร: ออกแบบระบบล็อกอินให้ SaaS ตั้งแต่วันแรก

Supabase Auth คืออะไร: ออกแบบระบบล็อกอินให้ SaaS ตั้งแต่วันแรก

หลายทีมเสียเวลาหลายสัปดาห์เขียนระบบล็อกอินเองตั้งแต่ศูนย์ ทั้งที่มีของสำเร็จรูปที่ปรับแต่งได้ลึกอยู่แล้ว บทความนี้อธิบายว่า Supabase Auth ทำงานยังไงและควรออกแบบ Authentication ของ SaaS อย่างไรให้รองรับการโตในอนาคต