JSON Response
ส่ง JSON response
หัวข้อที่มีชื่อว่า “ส่ง JSON response”ใน Express คุณเรียก res.status(200).json(payload) ส่วนใน Echo ใช้ c.JSON(statusCode, payload) และ Echo ตั้ง header Content-Type: application/json ให้อัตโนมัติ
// Expressapp.get('/books/:id', (req, res) => { const book = { id: req.params.id, title: 'Go in Action' }; res.status(200).json(book);});
// 404res.status(404).json({ message: 'not found' });// Echofunc getBook(c echo.Context) error { book := map[string]string{ "id": c.Param("id"), "title": "Go in Action", } return c.JSON(http.StatusOK, book)}
// 404 (ผ่าน HTTPError — ดูในบท Error Handling)return echo.NewHTTPError(http.StatusNotFound, "not found")Typed response struct
หัวข้อที่มีชื่อว่า “Typed response struct”การใช้ map[string]string สะดวกสำหรับตัวอย่าง แต่โค้ด production ควรใช้ typed response struct เพื่อให้ compiler จับ typo ของชื่อ field ได้ และทำให้ API surface ถูก document ไว้ในโค้ดเอง
// TypeScript — response typeinterface BookResponse { id: string; title: string; author: string; publishedAt: string; // ISO 8601}
const toResponse = (b: Book): BookResponse => ({ id: b.id, title: b.title, author: b.author, publishedAt: b.createdAt.toISOString(),});
res.json(toResponse(book));// Go — response structtype BookResponse struct { ID string `json:"id"` Title string `json:"title"` Author string `json:"author"` PublishedAt string `json:"publishedAt"` // RFC 3339 / ISO 8601}
func toBookResponse(b Book) BookResponse { return BookResponse{ ID: b.ID, Title: b.Title, Author: b.Author, PublishedAt: b.CreatedAt.UTC().Format(time.RFC3339), }}
return c.JSON(http.StatusOK, toBookResponse(book))HTTP status code มาตรฐาน
หัวข้อที่มีชื่อว่า “HTTP status code มาตรฐาน”Echo re-export constant จาก net/http ของ Go ใช้ชื่อ constant แทนตัวเลขดิบ
http.StatusOK // 200http.StatusCreated // 201http.StatusNoContent // 204http.StatusBadRequest // 400http.StatusUnauthorized // 401http.StatusForbidden // 403http.StatusNotFound // 404http.StatusConflict // 409http.StatusUnprocessableEntity // 422http.StatusInternalServerError // 500ลองใช้งาน — JSON marshal/unmarshal
หัวข้อที่มีชื่อว่า “ลองใช้งาน — JSON marshal/unmarshal”encoding/json คือ engine ที่อยู่เบื้องหลัง c.JSON ลองใช้โดยตรง:
package main
import ( "encoding/json" "fmt" "time")
type BookResponse struct { ID string `json:"id"` Title string `json:"title"` Author string `json:"author"` PublishedAt time.Time `json:"publishedAt"`}
func main() { book := BookResponse{ ID: "abc-123", Title: "The Go Programming Language", Author: "Donovan & Kernighan", PublishedAt: time.Date(2015, 10, 26, 0, 0, 0, 0, time.UTC), }
// Marshal เป็น JSON (สิ่งที่ c.JSON ทำภายใน) data, err := json.MarshalIndent(book, "", " ") if err != nil { fmt.Println("marshal error:", err) return } fmt.Println(string(data))
// Unmarshal กลับ var decoded BookResponse if err := json.Unmarshal(data, &decoded); err != nil { fmt.Println("unmarshal error:", err) return } fmt.Printf("\nDecoded title: %s\n", decoded.Title) fmt.Printf("Published: %s\n", decoded.PublishedAt.Format(time.RFC3339))}Loading Go runtime (first run only, ~8 MB)…
List response และ pagination
หัวข้อที่มีชื่อว่า “List response และ pagination”อย่า return JSON array เปล่า ๆ ที่ top level — ห่อด้วย object เสมอ เพื่อให้เพิ่ม metadata ทีหลังได้โดยไม่ต้อง break API
// Express — paginated listres.json({ data: books, total: count, page: Number(req.query.page ?? 1), limit: Number(req.query.limit ?? 10),});// Echo — paginated listtype PaginatedBooks struct { Data []BookResponse `json:"data"` Total int `json:"total"` Page int `json:"page"` Limit int `json:"limit"`}
return c.JSON(http.StatusOK, PaginatedBooks{ Data: responses, Total: total, Page: page, Limit: limit,})