RRuna

HTTP 路由

注册路由、分组、域和强类型处理器

route 是 Runa 的 HTTP 传输模块。Runa 内核不自带 HTTP,只有安装 route.Provider() 后,应用才会启动 HTTP 服务。

如果你刚开始写 Go Web,可以先把 route 理解成三件事:注册路径、处理请求、写出响应。

安装

go get github.com/duxweb/runa/route

如果还没有安装内核,一起安装:

go get github.com/duxweb/runa github.com/duxweb/runa/route

接入应用

package main

import (
    "context"

    "github.com/duxweb/runa"
    "github.com/duxweb/runa/route"
)

func main() {
    app := runa.New()
    app.Install(route.Provider(route.Addr(":8080")))

    route.Default().Get("/", func(ctx *route.Context) error {
        return ctx.Text("Hello Runa")
    })

    if err := app.Run(context.Background()); err != nil {
        panic(err)
    }
}

route.Provider 会注册默认路由表、HTTP Host 和 route:list 命令。

启动输出

HTTP Host 启动成功后,route 会在控制台输出 Runa 标识、URL、绑定地址、环境、Host 单元名、PID、路由数量,以及自动识别到的 Console、OpenAPI、Docs、Observe 等工具入口。

serve 启动 Host 单元后,Runa 还会输出 Hosts 区块,用来查看 HTTP、WebSocket、队列 worker 等长期运行单元是否已经启动。

如果你的进程管理器不希望看到启动界面,可以关闭:

app.Install(route.Provider(
    route.Addr(":8080"),
    route.Banner(false),
))

注册路由

route.Default().Get("/", home)
route.Default().Post("/users", createUser)
route.Default().Put("/users/{id}", updateUser)
route.Default().Patch("/users/{id}", patchUser)
route.Default().Delete("/users/{id}", deleteUser)

路径里的 {id} 是路径参数,可以在 handler 里读取:

func showUser(ctx *route.Context) error {
    id := ctx.Param[string]("id")
    return ctx.JSON(runa.Map{"id": id})
}

分组

分组适合给一批路由加同一个前缀、中间件、名称或文档标签。

api := route.Default().Group("/api").Name("api").Tags("API")
api.Get("/users", listUsers).Name("users.index")
api.Get("/users/{id}", showUser).Name("users.show")

实际路径会变成:

GET /api/users
GET /api/users/{id}

域适合后台、开放平台、内部接口这类大入口分区。

admin := route.Default().Domain("admin", "/admin")
admin.Get("/", dashboard).Name("dashboard")

这里的 domain 不是 DNS 域名,而是 Runa 对一组路由的逻辑分区。

强类型路由

普通 handler 写起来快,强类型路由更适合业务接口。

type GetUserInput struct {
    ID string `param:"id"`
}

type GetUserOutput struct {
    ID   string `json:"id"`
    Name string `json:"name"`
}

route.Get[GetUserInput, GetUserOutput](
    route.Default(),
    "/users/{id}",
    func(ctx *route.Context, input *GetUserInput) (*GetUserOutput, error) {
        return &GetUserOutput{ID: input.ID, Name: "Runa"}, nil
    },
).Name("user.show").Summary("用户详情").Tags("User")

强类型路由会自动绑定输入、渲染输出,并把 schema 写入路由元数据,方便后续生成 OpenAPI。

独立 New 使用

不接入 Runa 应用时,也可以独立创建路由表:

registry := route.New()
registry.Get("/", func(ctx *route.Context) error {
    return ctx.Text("ok")
})

if err := http.ListenAndServe(":8080", registry.Handler()); err != nil {
    panic(err)
}

这种方式只使用 route,不走 Runa 应用生命周期,适合非常小的实验或嵌入到已有 net/http 项目。

查看路由

接入 route.Provider 后,可以查看已注册路由:

go run . route:list

常见错误

route.Default() panic

通常是没有安装 route.Provider(...)。先安装 route,再注册路由。

路由写在全局变量里

不要在包级变量初始化时注册路由。推荐在 main 或业务 Module 的 Register 阶段注册。

不知道该用普通 handler 还是强类型路由

简单页面或健康检查用普通 handler。业务 API、需要 OpenAPI、需要请求验证时,用强类型路由。

编辑此页