core/internal/port/handler_http_api.go

117 lines
3.4 KiB
Go

package port
import (
"net/http"
"sync"
"gitea.dwysokinski.me/twhelp/core/internal/app"
"gitea.dwysokinski.me/twhelp/core/internal/port/internal/apimodel"
"gitea.dwysokinski.me/twhelp/core/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
ennoblementSvc *app.EnnoblementService
tribeChangeSvc *app.TribeChangeService
tribeSnapshotSvc *app.TribeSnapshotService
playerSnapshotSvc *app.PlayerSnapshotService
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,
ennoblementSvc *app.EnnoblementService,
tribeChangeSvc *app.TribeChangeService,
tribeSnapshotSvc *app.TribeSnapshotService,
playerSnapshotSvc *app.PlayerSnapshotService,
opts ...APIHTTPHandlerOption,
) http.Handler {
cfg := newAPIHTTPHandlerConfig(opts...)
h := &apiHTTPHandler{
versionSvc: versionSvc,
serverSvc: serverSvc,
tribeSvc: tribeSvc,
playerSvc: playerSvc,
villageSvc: villageSvc,
ennoblementSvc: ennoblementSvc,
tribeChangeSvc: tribeChangeSvc,
tribeSnapshotSvc: tribeSnapshotSvc,
playerSnapshotSvc: playerSnapshotSvc,
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,
h.villageMiddleware,
},
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: apimodel.ErrorCodeRouteNotFound,
message: "route not found",
})
}
func (h *apiHTTPHandler) handleMethodNotAllowed(w http.ResponseWriter, r *http.Request) {
h.errorRenderer.render(w, r, apiError{
status: http.StatusMethodNotAllowed,
code: apimodel.ErrorCodeMethodNotAllowed,
message: "method not allowed",
})
}