A Gin middleware that automatically detects and exposes the server's hostname and scheme by inspecting the incoming http.Request. This is particularly useful when your application runs behind proxies or load balancers, as it intelligently determines the correct public-facing URL.
X-Forwarded-Proto, X-Forwarded-Host)The middleware examines the request in the following order to determine the scheme and host:
Scheme Detection:
X-Forwarded-Proto header (or custom configured header)Host Detection:
X-Forwarded-Host)X-Host headerHost headerDownload and install it:
go get github.com/gin-contrib/location/v2
Import it in your code:
import "github.com/gin-contrib/location/v2"
Use location.Default() for quick setup with sensible defaults:
package main
import (
"fmt"
"net/http"
"github.com/gin-contrib/location/v2"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
// Configure with default settings:
// - Scheme: defaults to "http"
// - Host: defaults to "localhost:8080"
// - Headers: X-Forwarded-Proto (scheme), X-Forwarded-Host (host)
router.Use(location.Default())
router.GET("/", func(c *gin.Context) {
url := location.Get(c)
// Access the detected URL components
fmt.Printf("Scheme: %s\n", url.Scheme) // e.g., "https"
fmt.Printf("Host: %s\n", url.Host) // e.g., "example.com"
fmt.Printf("Path: %s\n", url.Path) // e.g., ""
c.String(http.StatusOK, "Full URL: %s", url.String())
})
router.Run(":8080")
}
Customize the middleware for your specific environment:
package main
import (
"fmt"
"net/http"
"github.com/gin-contrib/location/v2"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
// Custom configuration for production environment behind a proxy
router.Use(location.New(location.Config{
Scheme: "https", // Default scheme when not detected
Host: "api.example.com", // Default host when not detected
Base: "/v1", // Base path for the application
Headers: location.Headers{
Scheme: "X-Forwarded-Proto", // Header for scheme detection
Host: "X-Forwarded-Host", // Header for host detection
},
}))
router.GET("/users", func(c *gin.Context) {
url := location.Get(c)
// With Base="/v1", url.Path will be "/v1"
// Full URL will be: https://api.example.com/v1
c.JSON(http.StatusOK, gin.H{
"message": "API endpoint",
"url": url.String(),
})
})
router.Run(":8080")
}
| Field | Type | Description | Default |
|---|---|---|---|
Scheme |
string |
Default scheme when not detected | "http" |
Host |
string |
Default host when not detected | "localhost:8080" |
Base |
string |
Base path for the application | "" |
Headers.Scheme |
string |
Header name for scheme detection | "X-Forwarded-Proto" |
Headers.Host |
string |
Header name for host detection | "X-Forwarded-Host" |
When running behind nginx, Apache, or other reverse proxies:
router.Use(location.New(location.Config{
Scheme: "https",
Host: "your-domain.com",
Headers: location.Headers{
Scheme: "X-Forwarded-Proto",
Host: "X-Forwarded-Host",
},
}))
For applications deployed in Kubernetes with an Ingress controller:
router.Use(location.New(location.Config{
Scheme: "https",
Host: "api.myapp.com",
Base: "/api", // If your ingress routes /api to this service
Headers: location.Headers{
Scheme: "X-Forwarded-Proto",
Host: "X-Forwarded-Host",
},
}))
Generate absolute URLs in your responses:
router.GET("/users/:id", func(c *gin.Context) {
userID := c.Param("id")
baseURL := location.Get(c)
// Build absolute URL for the resource
userURL := fmt.Sprintf("%s/users/%s", baseURL.String(), userID)
c.JSON(http.StatusOK, gin.H{
"id": userID,
"self": userURL,
})
})
Default() gin.HandlerFuncReturns the location middleware with default configuration (HTTP scheme, localhost:8080 host).
New(config Config) gin.HandlerFuncReturns the location middleware with custom configuration.
Get(c *gin.Context) *url.URLRetrieves the location information from the Gin context. Returns nil if the middleware is not configured.
Returns: A *url.URL with the following fields:
Scheme: The detected or configured scheme (http/https)Host: The detected or configured host (including port if present)Path: The configured base pathConfigConfiguration structure for the middleware:
type Config struct {
Scheme string // Default scheme (e.g., "https")
Host string // Default host (e.g., "example.com:443")
Base string // Base path (e.g., "/api/v1")
Headers Headers // Custom headers for detection
}
HeadersHeader configuration for scheme and host detection:
type Headers struct {
Scheme string // Header name for scheme (default: "X-Forwarded-Proto")
Host string // Header name for host (default: "X-Forwarded-Host")
}
If you're upgrading from v1, simply update your import path:
- import "github.com/gin-contrib/location"
+ import "github.com/gin-contrib/location/v2"
The API remains fully backward compatible. No code changes are required.
We welcome contributions! Here's how you can help:
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)Please ensure:
go test -v ./...)go fmt ./...)golangci-lint run)This project is licensed under the MIT License - see the LICENSE file for details.
$ claude mcp add location \
-- python -m otcore.mcp_server <graph>