core/internal/port/handler_http_api.go

104 lines
2.8 KiB
Go

package port
import (
"net/http"
"sync"
"gitea.dwysokinski.me/twhelp/corev3/internal/app"
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/swgui"
"github.com/getkin/kin-openapi/openapi3"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
type apiHTTPHandler struct {
versionSvc *app.VersionService
serverSvc *app.ServerService
tribeSvc *app.TribeService
playerSvc *app.PlayerService
villageSvc *app.VillageService
errorRenderer apiErrorRenderer
openAPISchema func() (*openapi3.T, error)
}
func WithOpenAPIConfig(oapiCfg OpenAPIConfig) APIHTTPHandlerOption {
return func(cfg *apiHTTPHandlerConfig) {
cfg.openAPI = oapiCfg
}
}
func NewAPIHTTPHandler(
versionSvc *app.VersionService,
serverSvc *app.ServerService,
tribeSvc *app.TribeService,
playerSvc *app.PlayerService,
villageSvc *app.VillageService,
opts ...APIHTTPHandlerOption,
) http.Handler {
cfg := newAPIHTTPHandlerConfig(opts...)
h := &apiHTTPHandler{
versionSvc: versionSvc,
serverSvc: serverSvc,
tribeSvc: tribeSvc,
playerSvc: playerSvc,
villageSvc: villageSvc,
openAPISchema: sync.OnceValues(func() (*openapi3.T, error) {
return getOpenAPISchema(cfg.openAPI)
}),
}
r := chi.NewRouter()
if cfg.openAPI.Enabled {
r.Group(func(r chi.Router) {
if cfg.openAPI.SwaggerEnabled {
r.HandleFunc("/v2/swagger", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, r.RequestURI+"/", http.StatusMovedPermanently)
})
r.Handle("/v2/swagger/*", swgui.Handler(
cfg.openAPI.BasePath+"/v2/swagger",
cfg.openAPI.BasePath+"/v2/openapi3.json",
))
}
r.Get("/v2/openapi3.json", h.sendOpenAPIJSON)
})
}
// these handlers must be set after the swagger/openapi routes
// because we don't want to override the default handlers for those routes
r.NotFound(h.handleNotFound)
r.MethodNotAllowed(h.handleMethodNotAllowed)
return apimodel.HandlerWithOptions(h, apimodel.ChiServerOptions{
BaseRouter: r,
Middlewares: []apimodel.MiddlewareFunc{
middleware.NoCache,
h.versionMiddleware,
h.serverMiddleware,
h.tribeMiddleware,
h.playerMiddleware,
},
ErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
h.errorRenderer.render(w, r, err)
},
})
}
func (h *apiHTTPHandler) handleNotFound(w http.ResponseWriter, r *http.Request) {
h.errorRenderer.render(w, r, apiError{
status: http.StatusNotFound,
code: "route-not-found",
message: "route not found",
})
}
func (h *apiHTTPHandler) handleMethodNotAllowed(w http.ResponseWriter, r *http.Request) {
h.errorRenderer.render(w, r, apiError{
status: http.StatusMethodNotAllowed,
code: "method-not-allowed",
message: "method not allowed",
})
}