Routing และ Handler
Handler signature
หัวข้อที่มีชื่อว่า “Handler signature”ใน Express handler รับ (req, res, next) ส่วนใน Echo ทุก handler ใช้ signature มาตรฐานเดียวกัน:
func(c *echo.Context) error*echo.Context รวม request, response writer, path parameter, query parameter และ helper method ไว้ด้วยกัน คืน nil เมื่อสำเร็จ หรือคืน error เพื่อให้ Echo จัดการ response กรณีล้มเหลว
// Express handlerapp.get('/books/:id', (req, res, next) => { const id = req.params.id; const book = findBook(id); if (!book) return res.status(404).json({ message: 'not found' }); res.json(book);});// Echo handlerfunc getBook(c *echo.Context) error { id := c.Param("id") book, err := findBook(id) if err != nil { return echo.NewHTTPError(http.StatusNotFound, "not found") } return c.JSON(http.StatusOK, book)}การลงทะเบียน route
หัวข้อที่มีชื่อว่า “การลงทะเบียน route”Routing API ของ Echo คล้าย Express มาก ชื่อ method แมปตรงกับ HTTP verb
// Expressapp.get('/books', listBooks);app.post('/books', createBook);app.get('/books/:id', getBook);app.put('/books/:id', updateBook);app.delete('/books/:id', deleteBook);// Echoe.GET("/books", listBooks)e.POST("/books", createBook)e.GET("/books/:id", getBook)e.PUT("/books/:id", updateBook)e.DELETE("/books/:id", deleteBook)Path parameter
หัวข้อที่มีชื่อว่า “Path parameter”c.Param("name") คืนค่า string ของ segment ที่ตั้งชื่อไว้ ใช้ colon :name เหมือนกับ Express
// Expressapp.get('/users/:id/posts/:postId', (req, res) => { const { id, postId } = req.params; res.json({ userId: id, postId });});// Echoe.GET("/users/:id/posts/:postId", func(c *echo.Context) error { userID := c.Param("id") postID := c.Param("postId") return c.JSON(http.StatusOK, map[string]string{ "userId": userID, "postId": postID, })})Query parameter
หัวข้อที่มีชื่อว่า “Query parameter”c.QueryParam("name") อ่านค่า query ตัวเดียว ส่วน c.QueryParams() คืนทั้งหมดเป็น url.Values (คือ map[string][]string) และ c.QueryParamOr("page", "1") ใช้ใส่ค่า default
// Expressapp.get('/books', (req, res) => { const { page = '1', limit = '10' } = req.query; res.json({ page, limit });});// Echoe.GET("/books", func(c *echo.Context) error { page := c.QueryParamOr("page", "1") limit := c.QueryParamOr("limit", "10") return c.JSON(http.StatusOK, map[string]string{ "page": page, "limit": limit, })})Parameter แบบมี type — ไม่ต้อง strconv เอง
หัวข้อที่มีชื่อว่า “Parameter แบบมี type — ไม่ต้อง strconv เอง”ใน Express คุณต้องแปลง req.params.id เอง Echo v5 มี generic helper ที่ parse และตรวจสอบให้ในครั้งเดียว แล้วคืน error ที่คุณเอาไปตอบ 400 ได้เลย:
e.GET("/items/:id", func(c *echo.Context) error { id, err := echo.PathParam[int](c, "id") if err != nil { return echo.NewHTTPError(http.StatusBadRequest, "id must be an integer") } limit, err := echo.QueryParamOr[int](c, "limit", 10) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, "limit must be an integer") } return c.JSON(http.StatusOK, map[string]int{"id": id, "limit": limit})})มีครบทุกแหล่งข้อมูล: echo.QueryParam[T], echo.QueryParams[T] (key ซ้ำหลายค่า), echo.FormValue[T] และ echo.PathParamOr[T]
ผูก handler เข้ากับ struct (แบบ NestJS controller)
หัวข้อที่มีชื่อว่า “ผูก handler เข้ากับ struct (แบบ NestJS controller)”NestJS controller เป็น class ส่วนใน Go รูปแบบ idiomatic คือ struct ที่มี method เป็นตัว handler แล้วทำ dependency injection ผ่าน field ของ struct
// NestJS controller@Controller('books')export class BooksController { constructor(private readonly booksService: BooksService) {}
@Get(':id') findOne(@Param('id') id: string) { return this.booksService.findOne(id); }}// Echo — handler struct (manual DI)type BookHandler struct { store BookStore}
func NewBookHandler(s BookStore) *BookHandler { return &BookHandler{store: s}}
func (h *BookHandler) Get(c *echo.Context) error { id := c.Param("id") book, err := h.store.FindByID(c.Request().Context(), id) if err != nil { return echo.NewHTTPError(http.StatusNotFound, err.Error()) } return c.JSON(http.StatusOK, book)}
// Registration in main.go:// bh := NewBookHandler(store)// e.GET("/books/:id", bh.Get)รันบนเครื่องของคุณ — ต้องการ Echo module และ network port