บันทึกการเรียน Golang วันที่ 9 - ทำ API ด้วย Chi
สวัสดีครับ ช่วงนี้ดองบทความไว้ ไม่ได้มาเขียนเลย วันนี้เลยขอมาเขียนบันทึกย้อนหลัง ที่เรียน Golang วันที่ 9 นะครับ หลังจากที่วันก่อนได้ลองใช้ gorilla/mux ไป

วันนี้ผมได้ลองตัว Chi ที่เป็น web framework อีกตัว ก่อนหน้านี้ผมลองดูรายชื่อ framework แล้ว พบว่ามีเยอะมากๆ แต่ขอเลือกตัวที่คล้ายๆ Express เนื่องจากผมเขียน Node.js มาก่อน น่าจะทำให้เข้าใจง่ายกว่า (ลังเลระหว่าง Fiber และ Chi) เลยเลือกตัวนี้ก่อน ค่อยไปลองดู Fiber ในวันถัดไป
Chi
เนื่องจากหัดเขียน Go ผมคิดว่าฝึกทำโปรเจ็คและก็เรียนรู้ตัวภาษาไปในตัวและรู้สึกว่าตัวผมเองถนัดแบบนี้ ก็เลยลองคิดทำ API ขึ้นมาง่ายๆ โดยใช้ Chi ดู
ติดตั้ง Chi ง่ายๆ:
go get -u github.com/go-chi/chi/v5
ตัว API ไม่มีอะไรเลยครับ ทำคล้ายๆกับของ วันที่ 8 เปลี่ยนจาก gorilla มาเป็น chi นั่นเอง ตัว Source Code ก็อยู่ท้ายบทความครับ และก็แบ่ง folder เป็นแต่ละวันแล้ว
Routes
กำหนด routes spec ไว้ดังนี้
GET /posts/{id}
POST /posts
GET /posts
GET /users
GET /users/{id}
กำหนด Struct
เนื่องจากว่าผมยังไม่ได้ต่อ database ฉะนั้น ตัว data ก็ทำการ initial แบบ hard code กันไป
package main
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
Active bool `json:"active"`
}
type Post struct {
ID string `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
AuthorID int `json:"author_id"`
}
type Error struct {
Message string `json:"message"`
}
var users = []User{
{ID: "1", Name: "John Doe", Username: "johndoe", Active: true},
{ID: "2", Name: "Jane Doe", Username: "janedoe", Active: true},
{ID: "3", Name: "Michael Jordan", Username: "michaeljordan", Active: true},
{ID: "4", Name: "John Smith", Username: "johnsmith", Active: true},
}
var posts = []Post{
{ID: "1", Title: "Hello World", Body: "This is my first post", AuthorID: 1},
{ID: "2", Title: "Hello World 2", Body: "This is my second post", AuthorID: 1},
{ID: "3", Title: "Hello World 3", Body: "This is my third post", AuthorID: 2},
{ID: "4", Title: "Hello World 4", Body: "This is my fourth post", AuthorID: 3},
}
Hello World Chi
ถ้าดูจากโค๊ด Hello World จะเห็นว่ามีความแอบคล้ายๆ Express (หรือจริงๆ น่าจะคล้ายๆ Koa ฝั่ง Node.js มากกว่าแฮะ)
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main() {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World!"))
})
http.ListenAndServe(":3000", r)
}
- ทำการสร้าง Router ด้วย
chi.NewRouter()
- กำหนด middleware ด้วย
Use()
คล้ายๆ express - handle HTTP method ตามชื่อ function ได้เลย
.Get('/path', handler)
ตัวอย่าง กำหนด route และ handler function
r.Get("/posts", FindAllPosts)
r.Post("/posts", CreateNewPost)
r.Get("/posts/{postID}", FindPostByID)
r.Get("/users", FindAllUsers)
r.Get("/users/{userID}", FindUserByID)
การ return JSON เราจะใช้ตัว middleware render ติดตั้ง:
go get -u github.com/go-chi/render
import มาใช้
import (
"github.com/go-chi/render"
)
ตัวอย่าง handler function ของ FindAllPosts
ใช้ render.JSON
ได้เลย รู้สึกว่าสะดวกกว่าการมานั่งปั้น struct json เอง หรือผมอาจจะยังไม่ชินมั้ง
func FindAllUsers(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, users)
}
การรับ URL Params
ใช้ chi.URLParam()
r.Get("/posts/{postID}", FindPostByID)
func FindPostByID(w http.ResponseWriter, r *http.Request) {
postID := chi.URLParam(r, "postID")
}
การรับ Body Payload
ใช้ render.DecodeJSON()
func CreateNewPost(w http.ResponseWriter, r *http.Request) {
var post Post
err := render.DecodeJSON(r.Body, &post)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("400 - Bad Request"))
return
}
}
จากตัวอย่างใน Doc เห็นว่าตัว Chi รองรับการทำ routing groups ได้
func main(){
r := chi.NewRouter()
// Public Routes
r.Group(func(r chi.Router) {
r.Get("/", HelloWorld)
r.Get("/{AssetUrl}", GetAsset)
r.Get("/manage/url/{path}", FetchAssetDetailsByURL)
r.Get("/manage/id/{path}", FetchAssetDetailsByID)
})
// Private Routes
// Require Authentication
r.Group(func(r chi.Router) {
r.Use(AuthMiddleware)
r.Post("/manage", CreateAsset)
})
}
หลังจากได้ลองเล่นไปเล็กน้อย ก็พบว่า ด้วยความที่มันมีความคล้าย Express เหมือนเราเขียน Node.js ทำให้การฝึกเขียน Go ไม่ได้มีความยากมากเท่าไหร่ และดูเข้าใจง่ายขึ้นเยอะ แน่นอน ผมยังไม่ได้เรียนรู้ตัวภาษา Go อีกเยอะมากมาย แต่ผมเน้นทำ โปรเจ็คเล็กๆ แล้วเรียนรู้ไปเรื่อยๆ ดีกว่า มันเห็นภาพมากกว่า อาจมีผิดบ้าง แต่ก็ได้ผลลัพธ์เป็นที่พอใจ
เดี๋ยวไว้วันต่อไป จะลองเอา API เดิม เริ่มไปต่อ Database ดูบ้างแล้วดีกว่า
Happy Coding ❤️
Source Code