goweb,基於go語言的API框架

Alber發表於2018-01-17

goweb

一個基於go語言的快速開發WebAPI的工具,這個工具受到了SpringMVC的啟發,結合了go語言本身的特性,整體比較簡單,接下來,看看如何使用它。

下載安裝:

go get github.com/alberliu/goweb

1.核心功能

請求體引數注入

package main

import "github.com/alberliu/goweb"

type User struct {
    Id   int    `json:"id"`
    Name string `json:"name"`
}

func handler(user User) User {
    return user
}

func main() {
    goweb.HandlePost("/test", handler)
    goweb.ListenAndServe(":8000")
}

請求體:

{
    "id": 1,
    "name": "alber"
}

響應體:

{
    "id": 1,
    "name": "alber"
}

上面的程式碼是一個最簡的例子,HandlePost(string, interface{})會將一個handler註冊到一個全域性的內建的goweb例項defultGoWeb,ListenAndServe(":8000")會將defultGoWeb賦給Server的handler變數,然後啟動這個Server。(是不是和內建的ServerMux有點像)

goweb會自動解析註冊到它本身的handler,當請求到來時,會將請求體的json資料反序列化並注入到handler的引數,handler處理完邏輯返回時,會將handler的返回值序列化為json資料返回。goweb預設使用json的序列化和反序列化方式,當然你可以定義自己的序列化方式,這個在後面你可以看到。

例子給出的handler的引數和返回都是結構體型別,當然你也可以使用指標型別。

結構體goweb其實本質上就是一個路由,它實現了Handler介面。上面的例子都是預設的defultGoWeb,你也可以自己例項化一個goweb。

func main() {
    goweb:=goweb.NewGoWeb();
    goweb.HandlePost("/test", handler)
    server := &http.Server{Addr: ":8000", Handler: goweb}
    server.ListenAndServe()
}

url引數注入

package main

import "github.com/alberliu/goweb"

type User struct {
    Id   int64  `json:"id"`
    Name string `json:"name"`
}

func handler(id int64, name string) User {
    return User{id, name}
}

func main() {
    goweb := goweb.NewGoWeb();
    goweb.HandleGet("/test/{id}/{name}", handler)
    goweb.ListenAndServe(":8000")
}

執行上面的程式碼,然後訪問url:http://localhost:8000/test/123456/alber

就可以返回下面的json資料

{
    "id": 123456,
    "name": "alber"
}

handler可以獲取到url中的引數,並且注入到handler引數中。handler的第一個引數對應url中的第一個引數,第二個引數對應url中的的第二個引數,依次類推。不過暫時還有個限制,在url中使用引數時,handler中的引數必須與url中的引數個數一致,且型別必須為string或者int64。

2.handler

goweb可以註冊多種形式的handler,goweb會利用反射自動解析函式,支援多種型別,但是不能超出它可以解析的範圍。以下是它所有能解析的型別。


func handler(ctx goweb.Context) {
}

func handler(ctx goweb.Context) User {
    return User{}
}

func handler(user User) User {
    return User{}
}

func handler(ctx goweb.Context, user User) User {
    return User{}
}

func handler(name string, id int64) User {
    return User{}
}

func handler(ctx goweb.Context, name string, id int64) User {
    return User{}
}

Context是一個請求上下文,他只有ResponseWriter和Request兩個欄位,它的內部結構如下所示。你可以根據自己的需求修改原始碼進行擴充套件,例如,把它作為一個請求的會話使用。

type Context struct {
    w http.ResponseWriter
    r *http.Request
}

3.用Group組織你的handler

func main() {
    group1:=goweb.NewGroup("/group1")
    group1.HandleGet("/handler1",handler)
    group1.HandleGet("/handler2",handler)
    group1.HandleGet("/handler3",handler)

    group2:=goweb.NewGroup("/group2")
    group2.HandleGet("/handler1",handler)
    group2.HandleGet("/handler2",handler)
    group2.HandleGet("/handler3",handler)

    group3:=goweb.NewGroup("/group3")
    group3.HandleGet("/handler1",handler)
    group3.HandleGet("/handler2",handler)
    group3.HandleGet("/handler3",handler)

    goweb.HandleGroup(group1)
    goweb.HandleGroup(group2)
    goweb.HandleGroup(group3)
    goweb.ListenAndServe(":8000")
}

group可以幫助你分層次的組織你的handler,使你的路由結構更清晰。

4.定義自己序列化和反序列化方式

var json = jsoniter.ConfigCompatibleWithStandardLibrary

func jsonUnmarshal(data []byte, v interface{}) error {
    return json.Unmarshal(data, v)
}

func jsonMarshal(v interface{}) ([]byte, error){
    return json.Marshal(v)
}

func main() {
    goweb:=goweb.NewGoWeb();
    goweb.Unmarshal=jsonUnmarshal
    goweb.Marshal=jsonMarshal

    goweb.ListenAndServe(":8000")

}

goweb預設採用json(使用的是開源的jsoniter)序列化和反序列化資料,goweb的Marshal、Unmarshal變數本身是一個函式.如果你想定義自己的序列化方式,只需要覆蓋掉它就行,就像上面那樣。

5.攔截器


func interceptor1(http.ResponseWriter, *http.Request) bool {
    return true
}
func interceptor2(http.ResponseWriter, *http.Request) bool {
    return true
}
func interceptor3(http.ResponseWriter, *http.Request) bool {
    return true
}

func main() {
    goweb := goweb.NewGoWeb();
    goweb.AddInterceptor(interceptor1)
    goweb.AddInterceptor(interceptor2)
    goweb.AddInterceptor(interceptor3)
    goweb.ListenAndServe(":8000")
}

goweb在執行handler之前,會執行一個或者多個interceptor,並且會根據AddInterceptor的先後順序執行,當interceptor返回true時,會接著往下執行,返回false時,會終止執行。

6.過濾器

func filter(w http.ResponseWriter, r *http.Request, f func(http.ResponseWriter, *http.Request)) {
    f(w, r)
}

func main() {
    goweb := goweb.NewGoWeb();
    goweb.Filter = filter
    goweb.ListenAndServe(":8000")
}

你可以給goweb新增一個過略器,在過濾器中,如果你想執行完自己的邏輯之後,執行handler,只需要呼叫f(w, r)。

7.自定義錯誤處理


func handler400(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(400)
    w.Write([]byte("bad request"))
}
func handler404(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(404)
    w.Write([]byte("url not found"))
}
func handler405(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(405)
    w.Write([]byte("method not found"))
}

func main() {
    goWeb := goweb.NewGoWeb()
    goWeb.Handler400 = handler400
    goWeb.Handler404 = handler404
    goWeb.Handler405 = handler405

    goweb.ListenAndServe(":8000")
}

當請求執行失敗時,goweb中給出了一些預設的錯誤處理方式,就像上面那樣。當然,你也可以定義一些自己錯誤處理方式。

寫在後面

如果你有什麼好的建議,可以發我郵箱,一起交流。

alber_liu@qq.com

相關文章