W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
從v2.0版本開始,框架的?Server
?組件提供了規(guī)范化的路由注冊(cè)方式,更加適合團(tuán)隊(duì)規(guī)范化的使用場(chǎng)景,實(shí)現(xiàn)了以下特性:
OpenAPIv3
?協(xié)議的接口文檔SwaggerUI
?頁面這里使用?YAML
?配置文件:?config.yaml
?
server:
address: ":8199"
openapiPath: "/api.json"
swaggerPath: "/swagger"
我們從一個(gè)簡(jiǎn)單的?Hello
?例子開始:
package main
import (
"context"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
type HelloReq struct {
g.Meta `path:"/hello" method:"get"`
Name string `v:"required" dc:"Your name"`
}
type HelloRes struct {
Reply string `dc:"Reply content"`
}
type Hello struct{}
func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {
g.Log().Debugf(ctx, `receive say: %+v`, req)
res = &HelloRes{
Reply: fmt.Sprintf(`Hi %s`, req.Name),
}
return
}
func main() {
s := g.Server()
s.Use(ghttp.MiddlewareHandlerResponse)
s.Group("/", func(group *ghttp.RouterGroup) {
group.Bind(
new(Hello),
)
})
s.Run()
}
拷貝這段代碼,我們運(yùn)行起來試試,終端輸出信息如下:
2021-11-19 23:31:35.277 25580: http server started listening on [:8199]
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
----------|---------|---------|--------|------------|-----------------------------------------------------------|--------------------
default | default | :8199 | ALL | /* | github.com/gogf/gf/v2/net/ghttp.MiddlewareHandlerResponse | GLOBAL MIDDLEWARE
----------|---------|---------|--------|------------|-----------------------------------------------------------|--------------------
default | default | :8199 | ALL | /api.json | github.com/gogf/gf/v2/net/ghttp.(*Server).openapiSpec-fm |
----------|---------|---------|--------|------------|-----------------------------------------------------------|--------------------
default | default | :8199 | GET | /hello | main.(*Hello).Say |
----------|---------|---------|--------|------------|-----------------------------------------------------------|--------------------
default | default | :8199 | ALL | /swagger/* | github.com/gogf/gf/v2/net/ghttp.(*Server).swaggerUI-fm | HOOK_BEFORE_SERVE
----------|---------|---------|--------|------------|-----------------------------------------------------------|--------------------
可以看到,除了我們的業(yè)務(wù)路由之外,?Server
?自動(dòng)幫我們注冊(cè)了兩個(gè)路由:?/api.json
?和?/swagger/*
?。前者是自動(dòng)生成的基于標(biāo)準(zhǔn)的?OpenAPIv3
?協(xié)議的接口文檔,后者是自動(dòng)生成?SwaggerUI
?頁面,方便開發(fā)者查看和調(diào)試。這兩個(gè)功能默認(rèn)是關(guān)閉的,開發(fā)者可以通過前面示例中的?openapiPath
?和?swaggerPath
?兩個(gè)配置項(xiàng)開啟。
接口文檔通過?OpenAPIv3
?協(xié)議生成,一般來說需要結(jié)合相應(yīng)的?UI
?工具查看,地址:http://127.0.0.1:8199/api.json
由于?OpenAPIv3
?協(xié)議是規(guī)范的接口定義協(xié)議,因此開發(fā)者根據(jù)協(xié)議內(nèi)容可以做很多事,例如:自定義?UI
?展示、?Client
?代碼生成、協(xié)議轉(zhuǎn)換等等。
我們來看看這個(gè)?SwaggerUI
?頁面:http://127.0.0.1:8199/swagger/
這里只有一個(gè)我們的路由地址以及對(duì)應(yīng)的輸入輸出結(jié)構(gòu)體。當(dāng)然,這只是個(gè)簡(jiǎn)單的示例,你可以在真實(shí)的項(xiàng)目中通過一些配置使得頁面更加豐富多彩。
我們接著在這個(gè)頁面上做下接口測(cè)試吧:
嗯,接口返回了一個(gè)固定數(shù)據(jù)格式的?Json
?內(nèi)容,但是能看到其中的?data
?為我們需要的返回結(jié)果。
等等,似乎漏掉了什么東西?是的,我們這里使用了一個(gè)?Server
?組件提供的中間件,它是拿來做什么的呢?我們開看看它的方法定義:
是的,它在我們沒有提供自定義的返回?cái)?shù)據(jù)格式處理中間件時(shí),使用了一個(gè)默認(rèn)的中間件處理我們的請(qǐng)求,并返回了一個(gè)默認(rèn)的數(shù)據(jù)格式。
從上面的例子中,我們可以看到,路由方法定義使用固定的格式:
func Handler(ctx context.Context, req *Request) (res *Response, err error)
其中輸入?yún)?shù)和輸出參數(shù)都是兩個(gè),并且都是必須的一個(gè)都不能少。簡(jiǎn)單介紹下:
參數(shù)
|
說明
|
注意事項(xiàng)
|
---|---|---|
ctx context.Context
|
上下文 | Server 組件會(huì)自動(dòng)從請(qǐng)求中獲取并傳遞給接口方法 |
req *Request
|
請(qǐng)求對(duì)象 |
就算沒有接收參數(shù)也要定義,因?yàn)檎?qǐng)求結(jié)構(gòu)體中不僅僅包含請(qǐng)求參數(shù)的定義,也包含了接口的請(qǐng)求定義。 |
res *Response
|
返回對(duì)象 |
就算沒有返回參數(shù)也要定義,因?yàn)榉祷亟Y(jié)構(gòu)體中不僅僅包含返回參數(shù)的定義,也可以包含接口返回定義。 |
err error
|
錯(cuò)誤對(duì)象 | Server 通過該參數(shù)判斷接口執(zhí)行成功或失敗。 |
在規(guī)范化路由注冊(cè)中,非常重要的是請(qǐng)求/返回結(jié)構(gòu)體的定義,在該結(jié)構(gòu)體不僅僅包含了輸入?yún)?shù)的定義,也包含了接口的定義,特別是路由地址、請(qǐng)求方法、接口描述等信息。為保證命名規(guī)范化,輸入數(shù)據(jù)結(jié)構(gòu)以?XxxReq
?方式命名,輸出數(shù)據(jù)結(jié)構(gòu)以?XxxRes
?方式命名。即便輸入或者輸出參數(shù)為空,也需要定義相應(yīng)的數(shù)據(jù)結(jié)構(gòu),這樣的目的一個(gè)是便于后續(xù)擴(kuò)展,另一個(gè)是便于接口信息的管理。
請(qǐng)求參數(shù)自動(dòng)轉(zhuǎn)換到請(qǐng)求數(shù)據(jù)結(jié)構(gòu),字段映射轉(zhuǎn)換不區(qū)分大小寫,也會(huì)自動(dòng)忽略特殊字符。
請(qǐng)求結(jié)構(gòu)體在進(jìn)入API接口執(zhí)行前將會(huì)被自動(dòng)執(zhí)行校驗(yàn),如果其中一條規(guī)則校驗(yàn)失敗,那么將終止后續(xù)規(guī)則的校驗(yàn)。校驗(yàn)功能使用的是框架統(tǒng)一的校驗(yàn)組件。
接口的數(shù)據(jù)返回處理需要設(shè)置統(tǒng)一的后置中間件,當(dāng)然也可以使用?Server
?默認(rèn)提供的數(shù)據(jù)返回中間件。開發(fā)者自定義中間件時(shí)可以參考?Server
?默認(rèn)提供的中間件。注意其中的一個(gè)重要的方法:
// GetHandlerResponse retrieves and returns the handler response object and its error.
// return type handlerResponse struct {
// Object interface{}
// Error error
// }
func (r *Request) GetHandlerResponse() interface{}
通過后置中間件執(zhí)行時(shí)通過請(qǐng)求對(duì)象的?GetHandlerResponse
?方法獲取當(dāng)前業(yè)務(wù)執(zhí)行的結(jié)果,并根據(jù)需要做相應(yīng)處理。
我們推薦使用對(duì)象化的方式來管理所有路由方法,并通過分組路由的?Bind
?方法執(zhí)行統(tǒng)一注冊(cè)。
需要注意的是,在規(guī)范化路由方式下,路由地址以及請(qǐng)求方式將由請(qǐng)求結(jié)構(gòu)體在?g.Meta
?中定義,通過分組路由可以定義分組下的所有路由前綴。
?Server
?組件自動(dòng)生成的接口文檔使用的是最新的?OpenAPIv3
?協(xié)議。
我們可以通過?RequestFromCtx
?/?g.RequestFromCtx
?方法從?ctx
?中獲取?Request
?對(duì)象。
方法定義:
func RequestFromCtx(ctx context.Context) *Request
使用示例:
func (c *cHello) Hello(ctx context.Context, req *apiv1.HelloReq) (res *apiv1.HelloRes, err error) {
g.RequestFromCtx(ctx).Response.Writeln("Hello World!")
return
}
一個(gè)接口應(yīng)當(dāng)只做一件事情,?HTTP Method
?是有意義的,一個(gè)接口支持多種?HTTP Method
?方式是接口設(shè)計(jì)不合理,在規(guī)范路由下不支持。建議重新審視接口設(shè)計(jì)。
如果確實(shí)需要注冊(cè)類似于?ALL
?這種請(qǐng)求處理路由,在標(biāo)準(zhǔn)的?OpenAPI
?協(xié)議里面不支持,可以不使用規(guī)范路由,而是使用普通的路由注冊(cè)方式,將方法定義為?func(r *ghttp.Request)
?即可。不同的路由注冊(cè)方式可以結(jié)合使用,雖然不是很推薦。
使用類型別名即可。
源碼地址:https://github.com/gogf/gf/tree/master/example/httpserver/response_with_json_array
結(jié)果示例:
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: