goswagger เบื้องต้น
Pallat Anchaleechamaikorn
Posted on February 8, 2024
คนที่เขียน API ด้วย Go ถ้าอยากจะทำ swagger ให้คนเข้ามากดๆเล่นได้ มันมีวิธีทำหลายท่ามากๆ วันนี้จะมาแนะนำท่าของคนขี้เกียจเขียน annotation ซึ่งผมพยายามลองมาหลายท่า(ซึ่งอาจจะยังไม่หมด) แต่ก็เจอท่านี้ ซึ่งเข้าใจได้ไม่ยาก ใช้ง่ายโดยใช้
ก่อนอื่นก็ไปดูการติดตั้งในเพจเขาก่อน https://goswagger.io/install.html ซึ่งผมเลือกใช้วิธี Installing from source นะครับ
ถ้าเราอ่าน docs เข้าก็จะมี blog อ้างอิงที่ Generate swagger specification from Go source code
แต่เดี๋ยวผมจะเล่าให้อ่านกันในแบบของผมดูว่าจะเข้าใจไหมนะครับ
หลังจากติดตั้งตามคู่มือเรียบร้อย เราจะได้คำสั่ง swagger
มาให้ใช้ โดยคำสั่งนี้มันจะสามารถ auto generate ไฟล์ swagger.yaml หรือ json ก็ได้จาก source code เพียงแต่ว่า เราอาจจะต้องไปเขียน aanotation (อีกแล้วเหรอ) แต่ว่าเขียนไม่เยอะเท่า swaggo
ก่อนอื่นให้เราไปสร้าง meta ของ docs(swagger) ไว้ที่ /docs/docs.go
ก็คือไปสร้างไดเร็คทอรี่ชื่อ docs
ไว้ที่ root ของ project แล้วสร้างไฟล์ docs.go ไว้ในนั้นนั่นเอง
ใน docs.go มีตัวอย่างให้แบบนี้ครับ
// Package classification MyApplication.
//
// Documentation of our MyApplication API.
//
// Schemes: http
// BasePath: /
// Version: 1.0.0
// Host: localhost:8080
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// Security:
// - key: []
//
// SecurityDefinitions:
// key:
// type: apiKey
// in: header
// name: Authorization
//
// swagger:meta
package docs
ตัวอย่างนี้ผมแก้ไขนิดหน่อยให้เหมาะกับที่ผมใช้ประจำ โดยเป็นการกำหนด basepath ให้เป็น localhost:8080 เพราะเวลาเรารันที่เครื่องเราจะได้ยิง API บนเครื่องเราได้เลย
ตรงส่วน security ปกติผมจะใช้ Authorization ใน header ก็เลยกำหนดลักษณะนี้ไว้ครับ
นี่เป็นส่วนของ meta ซึ่งจะเป็นเหมือนหัวเอกสารของเราว่ามันเป็น API ของอะไร(ในตัวอย่างคือชื่อ MyApplication)
จากนั้น เราจะไปเขียน route พร้อมกับ request/response กัน ซึ่งเราสามารถจะไปเขียนไว้ที่ไหนก็ได้ใน codebase ของเรา แล้วเดี๋ยวเราจะใช้คำสั่ง swagger
ไป scan หามาให้เองครับ
ยกตัวอย่างเช่น ผมจะไปเขียน Handler ไว้ที่ ./app/user
ผมใช้วิธีไปสร้างไฟล์ docs.go ไว้ในนั้นอีกที เพื่อจะได้รู้ว่านี่คือส่วนของ docs โดยผมเขียนแบบนี้
package user
// swagger:route GET /users user getUserEndpointID
// responses:
//
// 200: userResponse
// 400: userBadRequestResponse
// 500: userErrorResponse
// swagger:response userResponse
type swaggerUserResponseWrapper struct {
// in:body
Body User
}
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
// swagger:response userBadRequestResponse
type swaggerUserBadRequestResponseWrapper struct {
// in:body
Body ErrorResponse
}
// swagger:response userErrorResponse
type swaggerUserErrorResponseWrapper struct {
// in:body
Body ErrorResponse
}
type ErrorResponse struct {
Message string `json:"message"`
}
อธิบายแบบนี้นะครับ
บรรทัด swagger:route syntax คือ
swagger:route [method] [path pattern] [?tag1 tag2 tag3] [operation id]
tag ก็คล้ายๆกับการจัดกลุ่ม โดยเราสามารถมีหลายๆ route ที่มี tag ชื่อเดียวกัน เราจะเห็นการจัดกลุ่มตาม tag ตอนที่เปิดหน้า swagger ขึ้นมา
operation id เป็น id ที่จะใช้ให้ input(parameter) refer ถึง จะได้รู้ว่าเป็น input ของ route ไหน
บรรทัด response: มันจะมีรายการของ response ว่า API ของเราจะมี response ได้กี่แบบ โดยจะกำหนดเป็น http status code จับคู่กับ response
บรรทัด swagger:response จะตามด้วยชื่อที่เราตั้ง โดยชื่อนี้จะถูกเอาไปจับคู่กับ status code ของ responses ด้านบน
บรรทัด //in:body เป็นการบอกว่า response ของเรานั้นเป็นแบบ Object โดยจะมี type User เป็นตัว represent ง่ายๆเลย เดี๋ยวมันจะสร้าง json ตาม struct ของ User ให้เอง
เอาแค่นี้ก่อน สมมุติว่า API ของเราเป็แบบ GET method แบบไม่ต้องส่งอะไรมาเลย แล้วจะได้ response ออกไปนะครับ หลังจากนี้เราจะไปใช้คำสั่ง swagger
กัน
swagger generate spec -o ./docs/swagger.yaml --scan-models
ผมใช้คำสั่งนี้เพื่อให้มัน scan หา annotation กับ model ต่างๆแล้วสร้างไฟล์ swagger.yaml ไปวางไว้ใน ./docs นะครับ
จากนั้นใช้คำสั่ง
swagger serve -F=swagger ./docs/swagger.yaml
มันจะ render Swagger แล้วเปิด browser ให้เราเลย
ทีนี้ โดยปกติ API เราก็อาจจะมีแบบ get โดยส่ง path parameter เข้ามา เราก็จะทำแบบนี้ครับ
// swagger:route GET /users/{id} user getUserEndpointID
// swagger:parameters getUserEndpointID
type swaggerUserParamsWrapper struct {
// Id of a User
//
// In: path
ID string `json:"id"`
}
แบบนี้ก็คือ เราจะรับค่า id เข้ามาเป็น path parameter
ต่อมา ถ้า request เข้ามาเป็น json ล่ะจะทำแบบไหน
// swagger:route POST /users user postUserEndpointID
// responses:
//
// 201:
// swagger:parameters postUserEndpointID
type swaggerAddUserParamsWrapper struct {
// in:body
Body User
}
ที่บรรทัด // swagger:parameters postUserEndpointID เราจับคู่ postUserEndpointID กับ route ที่ ID เดียวกัน
นี่เป็นตัวอย่างเบื้องต้นนะครับ เมื่อเราได้ swagger.yaml มาแล้ว สำหรับคนที่ใช้ vscode ถ้ามี extension ก็จะสามารถ try ใน vscode ได้เลย ไม่ต้องให้ swagger serve ด้วย สะดวกสุดๆ
สำหรับรายละเอียดเพิ่มเติมต่างๆ อ่านใน document ของ goswagger ได้เลย ซึ่งก็มีไม่ครบ 🤣 ถ้าอยากได้อะไร google หาเพิ่มเองด้วยก็ดีครับ
หวังว่าจะเป็นประโยชน์นะครับ
Posted on February 8, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024