Files
go-omni/app/router.go

159 lines
6.2 KiB
Go

package app
import (
"net/http"
"git.yuntuo.hk/k2safe/go-omni/contract"
"git.yuntuo.hk/k2safe/go-omni/httpx"
"git.yuntuo.hk/k2safe/go-omni/logx"
"git.yuntuo.hk/k2safe/go-omni/response"
)
func (a *App) handle(routes httpx.RouterGroup, method, path string, handler httpx.Handler, middleware []httpx.Middleware) {
routes.Handle(method, path, a.adapt(handler, middleware...))
}
func (a *App) adapt(handler httpx.Handler, middleware ...httpx.Middleware) http.Handler {
return a.adaptResponse(a.responseEncoder, handler, middleware...)
}
func (a *App) adaptResponse(encoder response.Encoder, handler httpx.Handler, middleware ...httpx.Middleware) http.Handler {
wrapped := handler
all := make([]httpx.Middleware, 0, len(a.middlewares)+len(middleware))
all = append(all, a.middlewares...)
all = append(all, middleware...)
for index := len(all) - 1; index >= 0; index-- {
if all[index] != nil {
wrapped = all[index](wrapped)
}
}
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
if a.config.LanguagePolicy != nil {
request = a.config.LanguagePolicy.Apply(writer, request)
}
request = request.WithContext(logx.WithLogger(contract.WithRequestPolicy(request.Context(), a.config.Request), a.config.LogInstance))
if len(a.config.TrustedProxies) > 0 {
request = request.WithContext(httpx.WithClientIPResolver(request.Context(), a.clientIPResolver))
}
requestContext := httpx.NewContext(request, writer, httpx.RouteParams(request.Context()))
requestContext.WithContext(httpx.WithRequestMetadata(request.Context(), httpx.RequestMetadata{
ClientIP: requestContext.ClientIP(), Method: request.Method, Route: httpx.RoutePattern(request.Context()),
}))
if provider, ok := a.responseEncoder.(response.ErrorRegistryProvider); ok {
requestContext.SetErrorRegistry(provider.ErrorRegistry())
}
requestContext.SetResponseEncoder(encoder)
requestContext.SetErrorLocalizer(a.config.ErrorLocalizer)
defer func() { httpx.CleanupMultipart(requestContext.Request()) }()
if err := wrapped(requestContext); err != nil {
a.writeError(requestContext, err)
}
})
}
// Handle registers an explicit method, including HEAD, OPTIONS and extension
// methods, through the same business middleware and error handling as GET.
func (a *App) Handle(method, path string, handler httpx.Handler, middleware ...httpx.Middleware) {
a.handle(a.router, method, path, handler, middleware)
}
// HandleWithResponse selects the route policy before all application middleware.
func (a *App) HandleWithResponse(method, path string, encoder response.Encoder, handler httpx.Handler, middleware ...httpx.Middleware) {
if encoder == nil {
encoder = a.responseEncoder
}
a.router.Handle(method, path, a.adaptResponse(encoder, handler, middleware...))
}
func (a *App) GET(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
a.handle(a.router, http.MethodGet, path, handler, middleware)
}
func (a *App) POST(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
a.handle(a.router, http.MethodPost, path, handler, middleware)
}
func (a *App) PUT(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
a.handle(a.router, http.MethodPut, path, handler, middleware)
}
func (a *App) PATCH(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
a.handle(a.router, http.MethodPatch, path, handler, middleware)
}
func (a *App) DELETE(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
a.handle(a.router, http.MethodDelete, path, handler, middleware)
}
func (a *App) Any(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
a.router.Any(path, a.adapt(handler, middleware...))
}
// RouterGroup scopes a route prefix and optional middleware.
type RouterGroup struct {
group httpx.RouterGroup
app *App
middlewares []httpx.Middleware
}
func (a *App) Group(path string, middleware ...httpx.Middleware) *RouterGroup {
return &RouterGroup{group: a.router.Group(path), app: a, middlewares: middleware}
}
func (g *RouterGroup) Use(middleware ...httpx.Middleware) *RouterGroup {
g.middlewares = append(g.middlewares, middleware...)
return g
}
func (g *RouterGroup) Group(path string, middleware ...httpx.Middleware) *RouterGroup {
combined := append([]httpx.Middleware{}, g.middlewares...)
combined = append(combined, middleware...)
return &RouterGroup{group: g.group.Group(path), app: g.app, middlewares: combined}
}
func (g *RouterGroup) route(method, path string, handler httpx.Handler, middleware []httpx.Middleware) {
combined := append([]httpx.Middleware{}, g.middlewares...)
combined = append(combined, middleware...)
g.app.handle(g.group, method, path, handler, combined)
}
// Handle registers an explicit method within this group's middleware chain.
func (g *RouterGroup) Handle(method, path string, handler httpx.Handler, middleware ...httpx.Middleware) {
g.route(method, path, handler, middleware)
}
func (g *RouterGroup) HandleWithResponse(method, path string, encoder response.Encoder, handler httpx.Handler, middleware ...httpx.Middleware) {
if encoder == nil {
encoder = g.app.responseEncoder
}
combined := append([]httpx.Middleware{}, g.middlewares...)
combined = append(combined, middleware...)
g.group.Handle(method, path, g.app.adaptResponse(encoder, handler, combined...))
}
func (g *RouterGroup) GET(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
g.route(http.MethodGet, path, handler, middleware)
}
func (g *RouterGroup) POST(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
g.route(http.MethodPost, path, handler, middleware)
}
func (g *RouterGroup) PUT(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
g.route(http.MethodPut, path, handler, middleware)
}
func (g *RouterGroup) PATCH(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
g.route(http.MethodPatch, path, handler, middleware)
}
func (g *RouterGroup) DELETE(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
g.route(http.MethodDelete, path, handler, middleware)
}
func (g *RouterGroup) Any(path string, handler httpx.Handler, middleware ...httpx.Middleware) {
combined := append([]httpx.Middleware{}, g.middlewares...)
combined = append(combined, middleware...)
g.group.Any(path, g.app.adapt(handler, combined...))
}