Binding และ Validation
Binding — อ่าน request body
หัวข้อที่มีชื่อว่า “Binding — อ่าน request body”ใน Express คุณเข้าถึง req.body (หลังจาก express.json()) ส่วนใน Echo c.Bind(&target) ทำงานแบบเดียวกัน: อ่าน Content-Type header แล้ว decode body เข้า struct ที่ส่งไป และยัง bind path param กับ query param ได้ด้วยถ้า field ใน struct มี tag ที่ถูกต้อง
// Express + TypeScriptinterface CreateBookDTO { title: string; author: string; year: number;}
app.post('/books', (req, res) => { const body = req.body as CreateBookDTO; // body.title, body.author, body.year พร้อมใช้ res.status(201).json(body);});// Echotype CreateBookRequest struct { Title string `json:"title"` Author string `json:"author"` Year int `json:"year"`}
func createBook(c echo.Context) error { var req CreateBookRequest if err := c.Bind(&req); err != nil { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } // req.Title, req.Author, req.Year พร้อมใช้ return c.JSON(http.StatusCreated, req)}Struct tag — ระบบ annotation ของ Go
หัวข้อที่มีชื่อว่า “Struct tag — ระบบ annotation ของ Go”Struct tag คือ string literal ที่แนบกับ field ทำงานคล้าย TypeScript decorator แต่ไม่ได้รันโค้ด — โค้ดจะอ่าน tag ตอน runtime ผ่าน reflection ตัว json:"name" คุมเรื่อง serialization ส่วน validate:"rule" ให้ validator library อ่านไปใช้
// TypeScript class-validatorimport { IsString, IsInt, Min, IsNotEmpty } from 'class-validator';
class CreateBookDTO { @IsString() @IsNotEmpty() title: string;
@IsString() author: string;
@IsInt() @Min(1000) year: number;}// Go struct tagtype CreateBookRequest struct { Title string `json:"title" validate:"required"` Author string `json:"author" validate:"required"` Year int `json:"year" validate:"required,min=1000"`}ลองใช้งาน — struct tag กับ encoding/json
หัวข้อที่มีชื่อว่า “ลองใช้งาน — struct tag กับ encoding/json”Package encoding/json ของ stdlib อ่าน json:"..." tag ระหว่าง Marshal/Unmarshal รันได้ใน playground:
package main
import ( "encoding/json" "fmt")
type Book struct { Title string `json:"title"` Author string `json:"author"` Year int `json:"year"` // omitempty: field ถูกละเว้นจาก JSON เมื่อเป็น zero/empty ISBN string `json:"isbn,omitempty"`}
func main() { // Unmarshal (JSON -> struct) raw := `{"title":"The Go Programming Language","author":"Donovan & Kernighan","year":2015}` var b Book if err := json.Unmarshal([]byte(raw), &b); err != nil { fmt.Println("error:", err) return } fmt.Printf("Title: %s\n", b.Title) fmt.Printf("Author: %s\n", b.Author) fmt.Printf("Year: %d\n", b.Year) fmt.Printf("ISBN: %q (empty — ละเว้นใน output)\n", b.ISBN)
// Marshal (struct -> JSON) out, _ := json.MarshalIndent(b, "", " ") fmt.Println(string(out))}Loading Go runtime (first run only, ~8 MB)…
Validation ด้วย go-playground/validator
หัวข้อที่มีชื่อว่า “Validation ด้วย go-playground/validator”Echo ไม่มี validation มาให้ในตัว แต่เปิด e.Validator ไว้ให้เสียบ validator เอง วิธีมาตรฐานคือเสียบ go-playground/validator เข้าไป
// NestJS global validation pipeimport { ValidationPipe } from '@nestjs/common';app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
// DTOclass CreateBookDTO { @IsString() @IsNotEmpty() title: string; @IsInt() @Min(1000) year: number;}// เชื่อม validator ครั้งเดียวใน main.goimport "github.com/go-playground/validator/v10"
type CustomValidator struct { v *validator.Validate}
func (cv *CustomValidator) Validate(i any) error { return cv.v.Struct(i)}
// ใน main():e.Validator = &CustomValidator{v: validator.New()}
// Handler — bind แล้ว validatefunc createBook(c echo.Context) error { var req CreateBookRequest if err := c.Bind(&req); err != nil { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } if err := c.Validate(req); err != nil { return echo.NewHTTPError(http.StatusUnprocessableEntity, err.Error()) } // req พร้อมใช้งานอย่างปลอดภัย return c.JSON(http.StatusCreated, req)}