package httpx import ( "io/fs" "net/http" "path" "strings" "github.com/gin-gonic/gin" ) func registerDocs(r *gin.Engine) { r.GET("/openapi.yaml", func(c *gin.Context) { c.Data(http.StatusOK, "application/yaml; charset=utf-8", openAPISpec) }) serve := func(c *gin.Context) { c.Data(http.StatusOK, "text/html; charset=utf-8", docsHTML) } r.GET("/docs", serve) r.GET("/docs/enums", serve) r.GET("/docs/errors", serve) r.GET("/docs/", func(c *gin.Context) { c.Redirect(http.StatusFound, "/docs") }) staticRoot, err := fs.Sub(docsStatic, "docs/static") if err != nil { panic("docs static embed: " + err.Error()) } serveStaticFile := func(name, contentType string) gin.HandlerFunc { return func(c *gin.Context) { b, err := fs.ReadFile(staticRoot, name) if err != nil { c.Status(http.StatusNotFound) return } c.Header("Cache-Control", "public, max-age=604800") c.Data(http.StatusOK, contentType, b) } } r.GET("/favicon.ico", serveStaticFile("favicon.ico", "image/x-icon")) r.GET("/apple-touch-icon.png", serveStaticFile("apple-touch-icon.png", "image/png")) r.GET("/docs/static/*filepath", func(c *gin.Context) { rel := strings.TrimPrefix(c.Param("filepath"), "/") rel = path.Clean("/" + rel) rel = strings.TrimPrefix(rel, "/") if rel == "" || strings.Contains(rel, "..") { c.Status(http.StatusNotFound) return } b, err := fs.ReadFile(staticRoot, rel) if err != nil { c.Status(http.StatusNotFound) return } ct := contentTypeFor(rel) c.Header("Cache-Control", "public, max-age=604800") c.Data(http.StatusOK, ct, b) }) } func contentTypeFor(name string) string { switch strings.ToLower(path.Ext(name)) { case ".png": return "image/png" case ".ico": return "image/x-icon" case ".svg": return "image/svg+xml" default: return "application/octet-stream" } }