From 4b16ea58d3a4af5428b811d89c9c5b961fde6ab7 Mon Sep 17 00:00:00 2001 From: Vaishnavi Iyer Date: Mon, 19 Jan 2026 14:50:52 +0530 Subject: [PATCH] refactor(docs): extract Swagger UI into template --- gateway/cache.go | 9 +++--- gateway/main.go | 54 +++++++++++++++++++++------------- gateway/redis.go | 2 +- gateway/templates/swagger.html | 18 ++++++++++++ 4 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 gateway/templates/swagger.html diff --git a/gateway/cache.go b/gateway/cache.go index f478e73..e552030 100644 --- a/gateway/cache.go +++ b/gateway/cache.go @@ -53,7 +53,7 @@ func CacheMiddleware() gin.HandlerFunc { c.Abort() return } - + var requestBody []byte var err error if c.Request.Body != nil { @@ -92,7 +92,7 @@ func CacheMiddleware() gin.HandlerFunc { c.Abort() return } - + // Validate text is not empty if req.Text == "" { c.JSON(400, gin.H{"error": "Invalid request", "message": "text field cannot be empty"}) @@ -112,8 +112,8 @@ func CacheMiddleware() gin.HandlerFunc { log.Printf("Cache HIT: %s", cacheKey) // Cache HIT! -> Verify Payment *BEFORE* serving - // verifyPayment creates its own timeout context, so pass request context directly - verifyResp, paymentCtx, err := verifyPayment(c.Request.Context(), signature, nonce) + // verifyPayment creates its own timeout context, so pass request context directly + verifyResp, paymentCtx, err := verifyPayment(c.Request.Context(), signature, nonce) if err != nil { log.Printf("Verification error on cache hit: %v", err) if errors.Is(err, context.DeadlineExceeded) { @@ -267,4 +267,3 @@ func (w *cachedWriter) WriteString(s string) (int, error) { w.body.WriteString(s) return w.ResponseWriter.WriteString(s) } - diff --git a/gateway/main.go b/gateway/main.go index 0608f4a..01b7aa7 100644 --- a/gateway/main.go +++ b/gateway/main.go @@ -8,15 +8,18 @@ import ( "context" "crypto/ecdsa" "crypto/sha256" + "embed" "encoding/base64" "encoding/hex" "encoding/json" "errors" "fmt" + "html/template" "io" "log" "net/http" "os" + "regexp" "strconv" "strings" "sync" @@ -29,6 +32,23 @@ import ( "github.com/joho/godotenv" ) +//go:embed templates/swagger.html +var swaggerTemplateFS embed.FS + +var swaggerTmpl = template.Must( + template.ParseFS(swaggerTemplateFS, "templates/swagger.html"), +) + +var swaggerVersionRe = regexp.MustCompile(`^\d+\.\d+\.\d+$`) + +func getSwaggerUIVersion() string { + v := os.Getenv("SWAGGER_UI_VERSION") + if swaggerVersionRe.MatchString(v) { + return v + } + return "5.11.0" +} + type PaymentContext struct { Recipient string `json:"recipient"` Token string `json:"token"` @@ -119,26 +139,18 @@ func main() { r.StaticFile("/openapi.yaml", "openapi.yaml") r.GET("/docs", func(c *gin.Context) { - c.Header("Content-Type", "text/html") - c.String(200, ` - - - - MicroAI Paygate Docs - - - -
- - - - -`) + data := struct { + Version string + }{ + Version: getSwaggerUIVersion(), + } + + c.Header("Content-Type", "text/html; charset=utf-8") + + if err := swaggerTmpl.Execute(c.Writer, data); err != nil { + c.String(500, "failed to render swagger ui") + return + } }) r.Use(cors.New(cors.Config{ @@ -233,7 +245,7 @@ func handleSummarize(c *gin.Context) { // Cache middleware always sets this as []byte, safe to assert requestBody = body.([]byte) } - + // Read body if not already available if requestBody == nil { // Read body with limit (only if middleware didn't process it) diff --git a/gateway/redis.go b/gateway/redis.go index 88d7745..7c83041 100644 --- a/gateway/redis.go +++ b/gateway/redis.go @@ -25,7 +25,7 @@ func initRedis() { // Parse Redis connection options redisURL := getEnv("REDIS_URL", "localhost:6379") var opts *redis.Options - + if strings.HasPrefix(redisURL, "redis://") || strings.HasPrefix(redisURL, "rediss://") { // Parse full Redis URL var err error diff --git a/gateway/templates/swagger.html b/gateway/templates/swagger.html new file mode 100644 index 0000000..98293fa --- /dev/null +++ b/gateway/templates/swagger.html @@ -0,0 +1,18 @@ + + + + MicroAI Paygate API Docs + + + +
+ + + + +