Files
lingniu-vehicle-ingest/vehicle-data-platform/apps/api/internal/openplatform/docs.go
2026-07-27 16:46:15 +08:00

84 lines
2.8 KiB
Go

package openplatform
import (
_ "embed"
"net/http"
"strconv"
"strings"
)
const (
OpenAPISpecPath = "/open-api/openapi.yaml"
SwaggerUIPath = "/open-api/swagger/"
SimpleDocsPath = "/open-api/docs/"
swaggerInitJSPath = "/open-api/swagger-init.js"
)
//go:embed assets/openapi.yaml
var openAPISpec []byte
//go:embed assets/swagger.html
var swaggerHTML []byte
//go:embed assets/swagger-init.js
var swaggerInitJS []byte
//go:embed assets/docs.html
var simpleDocsHTML []byte
// WithDocs exposes version-matched API documentation without requiring a
// production database connection or an authenticated platform session.
func WithDocs(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/open-api":
redirectDocs(w, r, SimpleDocsPath)
case "/open-api/swagger":
redirectDocs(w, r, SwaggerUIPath)
case "/open-api/docs":
redirectDocs(w, r, SimpleDocsPath)
case OpenAPISpecPath:
serveDocsAsset(w, r, "application/yaml; charset=utf-8", openAPISpec, "")
case SwaggerUIPath:
serveDocsAsset(w, r, "text/html; charset=utf-8", swaggerHTML,
"default-src 'none'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data:; connect-src 'self'; font-src https://cdn.jsdelivr.net; base-uri 'none'; frame-ancestors 'none'; form-action 'none'")
case swaggerInitJSPath:
serveDocsAsset(w, r, "application/javascript; charset=utf-8", swaggerInitJS, "")
case SimpleDocsPath:
serveDocsAsset(w, r, "text/html; charset=utf-8", simpleDocsHTML,
"default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; frame-ancestors 'none'; form-action 'none'")
default:
next.ServeHTTP(w, r)
}
})
}
func redirectDocs(w http.ResponseWriter, r *http.Request, target string) {
if r.Method != http.MethodGet && r.Method != http.MethodHead {
w.Header().Set("Allow", "GET, HEAD")
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
http.Redirect(w, r, target, http.StatusPermanentRedirect)
}
func serveDocsAsset(w http.ResponseWriter, r *http.Request, contentType string, body []byte, csp string) {
if r.Method != http.MethodGet && r.Method != http.MethodHead {
w.Header().Set("Allow", "GET, HEAD")
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
w.Header().Set("Content-Type", contentType)
w.Header().Set("Cache-Control", "no-store")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("Referrer-Policy", "no-referrer")
if strings.TrimSpace(csp) != "" {
w.Header().Set("Content-Security-Policy", csp)
}
w.Header().Set("Content-Length", strconv.Itoa(len(body)))
w.WriteHeader(http.StatusOK)
if r.Method == http.MethodGet {
_, _ = w.Write(body)
}
}