《Packt.Mastering.Go.Web.Services.2015.4.pdf》之Handling our API versions

本文介绍如何使用Gorilla Mux库在Go语言中区分不同的数据类型,以及通过JAS库实现自动化的RESTful API路由管理。包括路径参数的处理、请求值的获取等关键操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用gorilla/mux区分数据类型

"github.com/gorilla/mux"

func handleVersion(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "hi, this is an http verison")
    vars := mux.Vars(req)
    fmt.Printf("%v", vars)
    category := vars["format"]
    fmt.Printf("%v", category)
    query := req.URL.Query()
    fmt.Printf("%v", query)
    Format := req.URL.Query()["format"]
    fmt.Printf("%v", Format)
}

func mainmux() {
    routes := mux.NewRouter()
    routes.HandleFunc("/api.{format:json|xml|txt}/usert", handleVersion).Methods("Get")
    http.Handle("/", routes)
    http.ListenAndServe(":8080", nil)
}

可以在handler中根据format来对传入的数据进行不同解码方法。

利用jas

https://github.com/coocood/jas/blob/master/README_ZH.md
https://godoc.org/github.com/coocood/jas

特性

  • 无需手动定义URL路由规则, 路由规则由资源struct名和方法名决定,保证了方法名和URL路径的一致性。

  • 生成所有已处理的URL路径,用”\n”分割,可以作为API参考资料或检测API的改变。

  • 非侵入式,JASrouter只是一个http.Handler,可以和其他http.Handler一起使用,或在一个服务端口使用用多个JAS router。

  • 支持HTTP Streaming, 可以保持长连接,向客户端发送实时数据,并在客户端关闭时得到通知。

  • 支持从JSON request body的任意深度的路径提取参数,可以像JSON RPC一样用。

  • 提取参数的同时进行基本的验证,支持验证整数,string的长度,string的rune长度,string正则匹配。

  • 如果验证失败,响应默认的包含参数名的消息,(可选)将错误用Common Log Format写入日志。

  • 把未处理的错误包装成InternalError类型,响应默认消息,将stacktrace和请求信息用Common Log Format写入日志,支持自定义的错误回调函数。

  • 错误使用interface类型,这样当自带的错误类型不能满足需求,可以自定义错误类型。

  • 支持gzip。

  • 丰富的配置选项。

第一条中,路由规则由struct名和方法名定义,参考如下样例

type Users struct {}

    func (*Users) Photo (ctx *jas.Context) {} // `GET /users/photo`

    func (*Users) PostPhoto (ctx *jas.Context) {} // `POST /users/photo`

    func (*Users) PostPost (ctx *jas.Context) {} // `POST /users/post`

    func (*Users) GetPost (ctx *jas.Context) {} // `GET /users/post`

    func (*Users) PutPhoto (ctx *jas.Context) {} // `PUT /users/photo`

    func (*Users) DeletePhoto (ctx *jas.Context) {} // `DELETE /users/photo`

可以看到,Users对应路径users,各个方法名对应子路径,并且方法名称的前缀Post,Get,Put,Delete对应HTT请求POST,GET,PUT,DELETE,如果不指定前缀的话,则默认对应GET的HTTP请求。这样的struct类型称为resource。
当应用启动的时候,可以将多个resouce传递给 jas.NewRouter得到一个jas.Router .

router := jas.NewRouter(new(Users), new(Posts), new(Photos)

然后可以对其进行配置:

    router.BasePath = "/v1/"
    router.EnableGzip = true

获取所有handle的路径:

fmt.Println(router.HandledPaths(true)) // true for with base path. false for without base path.

设置路由和监听:

    http.Handle(router.BasePath, router)
    http.ListenAndServe(":8080", nil)

完整样例:

import "github.com/coocood/jas"
type Hello struct{}

func (*Hello) Get(ctx *jas.Context) {
    ctx.Data = "helloworld"

}

func main() {
    route := jas.NewRouter(new(Hello))
    route.BasePath = "/v1/"
    fmt.Println(route.HandledPaths(true))
    http.Handle(route.BasePath, route)
    http.ListenAndServe(":8080", nil)

}

路径中添加id

如果给resource的名字后面带上Id的后缀,那么在生成的路径,resouce名称和method名称的路径中间会多一个id的路径,这个id可以通过ctx.Id获取。

type UsersId struct {}

func (*UsersId) Photo (ctx *jas.Context) {// `GET /users/:id/photo`
    id := ctx.Id
    _ = id
}

完整样例

type Hello struct{}

func (*Hello) Get(ctx *jas.Context) {
    ctx.Data = "helloworld"
}

type UserId struct{}

func (*UserId) Photo(ctx *jas.Context) { // `GET /users/:id/photo`
    id := ctx.Id
    ctx.Data = id
    fmt.Println(id)
}

func main() {
    route := jas.NewRouter(new(Hello), new(UserId))
    route.BasePath = "/v1/"
    fmt.Println(route.HandledPaths(true))
    http.Handle(route.BasePath, route)
    http.ListenAndServe(":8080", nil)

}

执行结果

GET /v1/hello
GET /v1/user/:id/photo
33

获取请求的值

jas含有许多方法获取请求数据的值,可以分为两类,以Find开头的方法和以Require开头的方法。当请求的参数无效时,以Find开头的方法会返回error,而以Require开头的方法会终止方法的执行并且相应错误信息。
https://godoc.org/github.com/coocood/jas里面 Users的方法是Photo,POST数据时一直提示404,应该更改为PostPhoto

func (*Users) Photo (ctx *jas.Context) {
    // will stop execution and response `{"data":null,"error":"nameInvalid"} if "name" parameter is not given..
    name := ctx.RequireString("name")
    age := ctx.RequirePositiveInt("age")
    grade, err := ctx.FindPositiveInt("grade")

    // 6, 60 is the min and max length, error message can be "passwordTooShort" or "passwordTooLong"
    password := ctx.RequireStringLen(6, 60, "password")

    // emailRegexp is a *regexp.Regexp instance.error message would be "emailInvalid"
    email := ctx.RequireStringMatch(emailRegexp, "email")
    _, _, _, _, _, _ = name, age, grade, err,password, email
}

完整测试代码,注意要

type Users struct{}

func (*Users) PostPhoto(ctx *jas.Context) {
    fmt.Println("begin")
    name := ctx.RequireString("name")
    fmt.Println(name)
    age := ctx.RequirePositiveInt("age")
    fmt.Println(age)
    grade, err := ctx.FindPositiveInt("grade")
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(grade)

    password := ctx.RequireStringLen(6, 60, "password")
    fmt.Println(password)
    // email := ctx.RequireStringMatch(ema)
}

func main() {
    route := jas.NewRouter(new(Hello), new(UserId), new(Users))
    route.BasePath = "/v1/"
    fmt.Println(route.HandledPaths(true))
    http.Handle(route.BasePath, route)
    http.ListenAndServe(":8080", nil)

}

测试数据

服务器端打印结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值