goweb,基于go的API框架

goweb

一个基于go语言开发API的工具,这个工具受到了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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容