跳转到内容

参考应用

reference/standard-service 是 Plumego 的规范应用形态。当问题是文件布局、路由归属,以及哪些结构可以安全复制到真实服务时,看这页。

如果还没有运行过服务,请先看开始使用。如果问题已经变成归属判断,请看仓库边界

reference/standard-service/
main.go
internal/
app/
app.go
routes.go
config/
config.go
handler/
api.go
health.go
文件 展示内容 可以复制的思路
main.go 加载配置、构建 app、注册路由、启动服务 启动顺序保持显式
internal/app/app.go 应用本地构造 依赖通过 constructor wiring
internal/app/routes.go 路由注册 一个 method、一个 path、一个 handler 保持可见
internal/config/config.go 服务本地配置 配置解析靠近应用,不放进稳定根
internal/handler/api.go JSON API handler 使用 net/http 签名和 contract 写回路径
internal/handler/health.go 存活/就绪 handler 健康端点保持小而传输层
1

启动入口

加载配置、构建 app、注册路由

2

构造应用

core.New 加应用本地依赖

3

加载配置

服务本地配置解析

4

处理请求

net/http handler 与 contract 写回

5

不要推导

归属规则在 docs/specs/tasks

main.go
-> config.Load()
-> app.New(cfg)
-> core.New(cfg.Core, dependencies)
-> 本地 handlers 和 dependencies
-> RegisterRoutes()
-> /healthz
-> /readyz
-> /api/v1/greet
-> Start()
func main() {
cfg := config.Load() // env → struct,显式,无全局变量
app := app.New(cfg) // 通过 constructor 注入依赖
app.RegisterRoutes() // 所有路由集中在一处
app.Start() // Prepare → ListenAndServe + 信号处理
}
type App struct {
Core *core.App
Handler *handler.APIHandler
}
func New(cfg *config.Config) *App {
logger := plog.NewLogger()
coreApp := core.New(core.DefaultConfig(), core.AppDependencies{Logger: logger})
return &App{
Core: coreApp,
Handler: handler.New(logger),
}
}

internal/app/routes.go — 一个 method、一个 path、一个 handler

Section titled “internal/app/routes.go — 一个 method、一个 path、一个 handler”
func (a *App) RegisterRoutes() {
a.Core.Get("/healthz", http.HandlerFunc(a.Handler.Health.Live))
a.Core.Get("/readyz", http.HandlerFunc(a.Handler.Health.Ready))
a.Core.Get("/api/v1/greet", http.HandlerFunc(a.Handler.API.Greet))
}

internal/handler/api.go — 标准库兼容的 handler

Section titled “internal/handler/api.go — 标准库兼容的 handler”
type APIHandler struct{ Logger log.Logger }
func (h APIHandler) Greet(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
if name == "" {
_ = contract.WriteError(w, r, contract.NewErrorBuilder().
Type(contract.TypeRequired).Detail("field", "name").Build())
return
}
_ = contract.WriteResponse(w, r, http.StatusOK,
map[string]string{"message": "hello, " + name}, nil)
}

可以安全复制 不应推导
显式启动顺序 每个应用都必须有完全相同的 internal 包
应用本地 constructor 和 路由注册 reference 负责仓库级边界
标准库 handler 签名 x/* 包属于默认路径
contract.WriteResponsecontract.WriteError 不要为每个功能另起一套响应 helper
只依赖稳定根的规范路径 已检入的实验扩展都拥有同等兼容性承诺
场景 是否使用这页
新建 Plumego 服务
校验 handler 和 route 形态
对比服务骨架
判断能力由哪个包负责 否,去看模块总览
判断兼容性或采用姿态 否,去看发布策略
下一个问题 页面
路由注册后请求如何流动? 请求流程
一项改动由哪个表面负责? 仓库边界
应该打开哪个模块? 模块总览
哪个包可以放心采用? 发布策略