mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 05:11:34 +00:00
- Add RateLimit, RequestValidation, and CORS middleware. - Configure middleware chain in API server. - Implement Redis cache for GraphQL Automatic Persisted Queries. - Add .golangci.yml and fix linting issues (shadowing, timeouts).
87 lines
2.8 KiB
Go
87 lines
2.8 KiB
Go
// Package http provides HTTP middleware and utilities.
|
|
package http
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// CORSMiddleware handles Cross-Origin Resource Sharing
|
|
func CORSMiddleware(allowedOrigins []string) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
origin := r.Header.Get("Origin")
|
|
allowed := false
|
|
|
|
// If no allowed origins configured, allow all (development mode usually)
|
|
if len(allowedOrigins) == 0 {
|
|
allowed = true
|
|
} else {
|
|
for _, o := range allowedOrigins {
|
|
if o == "*" || o == origin {
|
|
allowed = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Safe default if we want to allow everything
|
|
if allowed {
|
|
// If origin is present, use it, otherwise *
|
|
if origin != "" {
|
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
|
} else {
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
}
|
|
|
|
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
|
w.Header().Set("Access-Control-Allow-Headers",
|
|
"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Client-ID, X-API-Key")
|
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
}
|
|
|
|
if r.Method == "OPTIONS" {
|
|
w.WriteHeader(http.StatusOK)
|
|
return
|
|
}
|
|
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|
|
|
|
// RequestValidationMiddleware performs basic request validation
|
|
func RequestValidationMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// Check Content-Type for POST requests to /query
|
|
if r.Method == "POST" && r.URL.Path == "/query" {
|
|
ct := r.Header.Get("Content-Type")
|
|
// GraphQL clients might send application/json; charset=utf-8
|
|
if !strings.Contains(ct, "application/json") {
|
|
// Some clients might send no content type or something else?
|
|
// Strictly enforcing application/json is good for security.
|
|
// But we should be careful not to break existing clients if they are sloppy.
|
|
// For now, let's enforce it as requested.
|
|
http.Error(w, "Content-Type must be application/json", http.StatusUnsupportedMediaType)
|
|
return
|
|
}
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// APIKeyMiddleware checks for X-API-Key header
|
|
// This is a placeholder for future external integrations.
|
|
// It allows requests with a valid API key to bypass other auth or strictly enforce it.
|
|
// Currently it is a pass-through as we don't have defined API keys in config yet.
|
|
func APIKeyMiddleware(validAPIKeys []string) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// If we had keys, we would check them here.
|
|
// apiKey := r.Header.Get("X-API-Key")
|
|
// validate(apiKey)
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|