Files
agentic-coding-workflow/internal/transport/http/router.go
T
2026-06-10 10:01:12 +08:00

70 lines
2.2 KiB
Go

package httpx
import (
"net/http"
"github.com/go-chi/chi/v5"
"log/slog"
"github.com/yan1h/agent-coding-workflow/internal/transport/http/middleware"
)
// RouterDeps bundles the dependencies needed to assemble the router.
// MVP exposes only liveness/readiness probe hooks; later phases (auth
// resolver, module handlers, etc.) will add fields here rather than
// growing NewRouter's signature.
type RouterDeps struct {
// HealthCheck is invoked from GET /healthz. Returning a non-nil
// error renders 503 with the error message as the body. If nil,
// /healthz unconditionally returns 200 "ok".
HealthCheck func(*http.Request) error
// ReadyCheck is invoked from GET /readyz with the same contract.
ReadyCheck func(*http.Request) error
// SPAHandler 为 nil 时禁用前端 fallback;非 nil 时挂到 chi NotFound,
// 把未匹配的请求交给 SPA handler 处理(静态文件 + index.html 回退)。
SPAHandler http.Handler
// Logger 用于 Recover 和 Logger 中间件。为 nil 时跳过日志相关中间件。
Logger *slog.Logger
}
// NewRouter builds the application's chi.Router with the standard
// liveness/readiness endpoints attached. The return type is the
// chi.Router interface (not *chi.Mux) so call sites depend only on
// behaviour shared with future routing layers.
func NewRouter(deps RouterDeps) chi.Router {
r := chi.NewRouter()
// 所有中间件必须在注册路由之前添加(chi 的强制要求)。
r.Use(middleware.RequestID)
if deps.Logger != nil {
r.Use(middleware.Recover(deps.Logger))
r.Use(middleware.Logger(deps.Logger))
}
r.Get("/healthz", func(w http.ResponseWriter, req *http.Request) {
if deps.HealthCheck != nil {
if err := deps.HealthCheck(req); err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
}
_, _ = w.Write([]byte("ok"))
})
r.Get("/readyz", func(w http.ResponseWriter, req *http.Request) {
if deps.ReadyCheck != nil {
if err := deps.ReadyCheck(req); err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
}
_, _ = w.Write([]byte("ok"))
})
if deps.SPAHandler != nil {
r.NotFound(deps.SPAHandler.ServeHTTP)
}
return r
}