การสร้าง API ด้วย Echo
ทำไมต้อง Echo?
หัวข้อที่มีชื่อว่า “ทำไมต้อง Echo?”ถ้าคุณมาจาก Node.js คุณคงคุ้นเคยกับแนวคิดของ HTTP framework แบบเบาอยู่แล้ว: ฟังก์ชันที่แมป path + verb ไปยัง handler, middleware pipeline และวิธี serialize JSON ฝั่ง Go ก็มี Echo เป็น framework แบบนั้น
| สิ่งที่ต้องการ | Node.js / Express | Go / Echo |
|---|---|---|
| หน่วยหลัก | (req, res, next) functions | func(c *echo.Context) error |
| Routing | app.get('/path', handler) | e.GET("/path", handler) |
| Middleware | app.use(fn) | e.Use(fn) |
| ตอบกลับ JSON | res.json({ … }) | c.JSON(200, payload) |
| ส่งต่อ error | next(err) | return err |
Echo แข่งขันกับ Fastify และ NestJS ในแง่แนวคิด แต่เป็น binary ที่ compile แล้วเพียงตัวเดียว ไม่มี runtime, ไม่มี VM และไม่มี node_modules เวลา cold-start คือไมโครวินาที ไม่ใช่วินาที
Echo vs ระบบนิเวศ Go
หัวข้อที่มีชื่อว่า “Echo vs ระบบนิเวศ Go”Go มีหลาย web framework (Gin, Chi, Fiber, stdlib net/http) Echo อยู่ในจุดที่พอดี:
- พื้นที่ผิวขนาดเล็ก — อ่าน source code ทั้งหมดได้ในสุดสัปดาห์เดียว
- Idiomatic — handler คืนค่า
errorตรงกับ pattern errors-as-values ของ Go - มี built-in ครบ — Logger, Recover, CORS, GZIP, BasicAuth มาพร้อมกัน
- เสถียร — Echo v5 (2026) คือ major version ปัจจุบัน ส่วน v4 ยังได้รับ security fix จนถึงสิ้นปี 2026
ย้ายมาจาก Echo v4?
หัวข้อที่มีชื่อว่า “ย้ายมาจาก Echo v4?”tutorial ส่วนใหญ่บนเว็บยังเป็น v4 อยู่ บทนี้ใช้ v5 (github.com/labstack/echo/v5, ต้องใช้ Go 1.25 ขึ้นไป) ความต่างที่คุณจะเจอ:
| v4 | v5 |
|---|---|
func(c echo.Context) error — Context เป็น interface | func(c *echo.Context) error — Context เป็น struct |
middleware.Logger(), e.Logger เป็น interface ของ Echo เอง | middleware.RequestLogger(), e.Logger เป็น *slog.Logger |
e.Logger.Fatal(e.Start(":1323")) | if err := e.Start(":1323"); err != nil { … } (หรือ echo.StartConfig สำหรับ graceful shutdown) |
e.HTTPErrorHandler = func(err error, c echo.Context) | e.HTTPErrorHandler = func(c *echo.Context, err error) |
err.(*echo.HTTPError) กับ echo.ErrNotFound | echo.StatusCode(err) — error สำเร็จรูปไม่ใช่ *HTTPError อีกแล้ว |
c.ParamNames() / c.ParamValues() | c.PathValues() และ helper แบบมี type echo.PathParam[int](c, "id") |
sed สองบรรทัดจัดการงาน migration ได้เกือบหมด: แทน echo/v4 ด้วย echo/v5 และแทน echo.Context ด้วย *echo.Context
// Express (Node.js)import express from 'express';const app = express();app.use(express.json());
app.get('/ping', (req, res) => { res.json({ message: 'pong' });});
app.listen(1323, () => console.log('listening'));// Echo (Go)package main
import ( "log/slog" "net/http" "os"
"github.com/labstack/echo/v5")
func main() { e := echo.New()
e.GET("/ping", func(c *echo.Context) error { return c.JSON(http.StatusOK, map[string]string{ "message": "pong", }) })
if err := e.Start(":1323"); err != nil { slog.Error("server stopped", "err", err) os.Exit(1) }}สิ่งที่เราจะสร้าง
หัวข้อที่มีชื่อว่า “สิ่งที่เราจะสร้าง”ตลอดบทนี้เราจะสร้าง Books REST API — สร้าง อ่าน อัปเดต และลบหนังสือ — ทีละขั้นตอน:
- สร้างโปรเจกต์ด้วย
go.modและmain.go - กำหนด route และฟังก์ชัน handler
- เพิ่ม middleware (logging, recovery, CORS)
- Bind request body และ validate ด้วย struct tag
- จัดรูปแบบ JSON response พร้อม status code
- จัดการ error แบบรวมศูนย์ — วิธีแบบ Go
- เชื่อมต่อฐานข้อมูลผ่าน
database/sql - เขียน handler test ด้วย
httptest
แต่ละบทสามารถอ่านได้แยกกัน แต่โปรเจกต์จะเติบโตขึ้นเรื่อย ๆ