MetaMessage,開啟了API革命!

傳統api調用存在很多問題。
- 很多應用,api是沒有文檔的,調用者根本無法得知api的請求參數和返回數據是什麼樣的,規範是什麼。
- 發佈一個api,可能還得發佈文檔,比如Swagger。大多數開發者很難寫好文檔,文檔質量參差不齊。
- 文檔發佈地址就是一個問題。即使有文檔,也很難找。還有一些文檔受限於網絡、權限等,看不了。
- 文檔可能和api脫節,更新不及時。甚至造成各種歧義。
- 文檔很難管理,丟失、遺忘等問題很常見。
- 開發者、調用者之間協作困難,甚至相互誤解。
…
問題太多了,這只是冰山一角。而MetaMessage的出現,可能真正改變了這種局面。
MetaMessage,自描述、自規範、自示例。比如,輸出為一個文本格式jsonc:
{
// mm: type=datetime; desc=創建時間
"create_time": "2026-01-01 00:00:00",
}
看起來很簡單,type表示了數據格式,各種語言實現一致,不會出現某個語言解釋為字符串的問題。desc可以描述字段含義、使用方法等。
當然還有更多標籤,這些標籤共同描述了一種精確、完整的數據。
開發者可以直接從各語言的數據對象直接生成mm,也可以通過比如jsonc字符串生成mm。代表的數據是完全一致的。
說到這裡,對於多語言間的數據對比,實際很困難,甚至說還沒有一個好的方法真正能做到,對於測試來說就是一個很大的問題。
而都轉成mm,對比文本非常方便。
還有一些其他的優點,比如可以生成緊湊的二進制,可以生成更多文本格式等等。未來,一個mm可以生成jsonc、toml、yaml等格式,作為配置文件的轉換非常方便。
遠了。
我們在調用一個api的時候,能不能直接獲取它的請求方法?我想到一個方法,我們可以利用resful的options方法。options方法設計之初就是資源探測,但是幾十年來,大家僅僅是用來表示cors,描述跨域問題。太浪費了。而且瀏覽器默認會在post等請求前,調用下options方法,我們是沒辦法取消的,有點可笑了。我們可以把請求參數方法放在options返回的body中,這樣調用方不就能獲得實時的、準確的請求方法了嗎?
OPTIONS /api/v1/users/1:
// mm: example
{
// mm: nullable; desc="用戶名稱"
"name": "",
// mm: type=email; nullable; desc="電子郵箱"
"email": "",
// mm: type=u8; nullable; desc="年齡"
"age": 0,
// mm: nullable; desc="是否激活"
"is_active": false,
}
這時一個修改用戶的api,當我們看到這個結果,我們就能知道name可以為null,age必須是uint8.當然整體上還能得出這是個example示例數據。
我們請求的時候,只要完全符合,那麼就是安全合法的。
實踐
我們來做一個golang gin的中間件,實現這樣的功能:
- 對於post、put、patch方法,把請求參數自動包裝、暴露到options
- 自動以mm對請求進行編碼
- 對返回結果自動解嗎
為了方便使用和演示,我們還可以做個客戶端:
- 請求的時候,自動探測schema,也就是請求options
- 自動驗證請求合法性
當然服務端和客戶端都會自動驗證。
server:
...
type CreateUserRequest struct {
Name string `mm:"desc=用戶名稱; min=1; max=50"`
Email string `mm:"type=email; desc=電子郵箱"`
Age uint8 `mm:"desc=年齡; min=0; max=150"`
}
mmgin.POST("/users", createUser)
func createUser(c *gin.Context, req *CreateUserRequest) {
newUser := User{
ID: int64(len(users) + 1),
Name: req.Name,
Email: req.Email,
Age: req.Age,
IsActive: true,
}
users = append(users, newUser)
mmgin.RespondWithStatus(c, http.StatusCreated, APIResponse{
Code: 0,
Message: "user created",
Data: &newUser,
}, "")
}
...
client:
...
type CreateUserRequest2 struct {
Name string `mm:"desc=用戶名稱; min=1; max=50"`
Email string `mm:"type=email; desc=電子郵箱"`
Age uint8 `mm:"desc=年齡; min=0; max=150"`
}
createReq := &CreateUserRequest2{
Name: "David",
Email: "david@example.com",
Age: 28,
}
resp3, err := client.POST[CreateUserRequest2, APIResponse]("/api/v1/users", createReq)
if err != nil {
fmt.Printf(" [Error] %v\n", err)
return
}
fmt.Printf(" [OK] Message: %s\n", resp3.Message)
fmt.Printf(" New User: %+v\n", resp3.Data)
...
以上可以看到,使用非常簡單,甚至無感。
完整示例可參見"metamessage/mm-gin"項目
可測試的結果是,只要請求數據不合法,在options階段就會失敗。
注意這是強一致的,是實時驗證的。
未來
api不用寫文檔,代碼就是文檔。
每個api接口,自動生成一個schema
陌生的api,沒關係,自動獲取請求參數;api更新,沒關係,自動獲得更新後的請求參數。
特別是眾多瀏覽器,怎麼也不會想到options還能這麼用,如果內置這種用法,對各種api更是幫助巨大。
MetaMessage作為基礎協議,會在各種場景有更多重要應用。
- 点赞
- 收藏
- 关注作者
评论(0)