Files
MusicServer/internal/server/routes.go
T
Sansan 6da96f79e7
CI / test (push) Successful in 28s
CI / integration (push) Successful in 39s
CI / publish (push) Skipped
CI / docker (push) Successful in 51s
Add a command to write the OpenAPI spec without a server
`just openapi [dir]` (go run ./cmd/openapi) writes openapi.json (3.1) and openapi-3.0.json without a database or configuration. A test checks it matches the spec the server serves.
2026-10-06 17:01:12 +02:00

82 lines
2.4 KiB
Go

package server
import (
"net/http"
"music-server/cmd/web"
"music-server/internal/logging"
"music-server/internal/server/middleware"
"github.com/a-h/templ"
"github.com/danielgtaylor/huma/v2"
"github.com/labstack/echo/v5"
echoMiddleware "github.com/labstack/echo/v5/middleware"
"go.uber.org/zap"
)
func (s *Server) RegisterRoutes() http.Handler {
e, _ := s.routes()
return e
}
// OpenAPISpec returns the API description. It needs no database or configuration:
// the handlers are registered but never called.
func OpenAPISpec() *huma.OpenAPI {
_, a := (&Server{}).routes()
return a.v1.OpenAPI()
}
func (s *Server) routes() (*echo.Echo, apis) {
e := echo.New()
e.HTTPErrorHandler = httpErrorHandler
if len(s.cfg.TrustedProxies) > 0 {
var trust []echo.TrustOption
for _, ipNet := range s.cfg.TrustedProxies {
trust = append(trust, echo.TrustIPRange(ipNet))
}
e.IPExtractor = echo.ExtractIPFromXFFHeader(trust...)
}
e.Use(logging.RequestLogger())
e.Use(echoMiddleware.Recover())
e.Use(echoMiddleware.CORSWithConfig(echoMiddleware.CORSConfig{
AllowOrigins: []string{"https://*", "http://*"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"},
AllowHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
AllowCredentials: true,
MaxAge: 300,
}))
// The API: /api/v1 is documented at /docs and /openapi.json; legacy routes are hidden.
a := newAPIs(e)
a.v1.UseMiddleware(middleware.ClientInfo, middleware.TokenAuth(a.v1, s.q, s.cfg.DisableSessionAuth))
a.legacy.UseMiddleware(middleware.ClientInfo, middleware.Deprecation)
s.registerToken(a)
s.registerMisc(a)
s.registerSync(a)
s.registerMusic(a)
s.registerLibrary(a)
s.registerStatistics(a)
// Older links to the spec and docs.
e.GET("/openapi", redirect("/openapi.json"))
e.GET("/swagger/*", redirect("/docs"))
// Search page and frontend.
e.GET("/assets/*", echo.WrapHandler(http.FileServer(http.FS(web.Assets))))
e.GET("/search", echo.WrapHandler(templ.Handler(web.SearchForm())))
e.POST("/find", echo.WrapHandler(web.NewSearchHandler(s.search)))
e.Static("/", s.cfg.FrontendPath)
for _, r := range e.Router().Routes() {
logging.GetLogger().Debug("Registered route", zap.String("method", r.Method), zap.String("path", r.Path))
}
return e, a
}
func redirect(to string) echo.HandlerFunc {
return func(c *echo.Context) error {
return c.Redirect(http.StatusMovedPermanently, to)
}
}