Heimdall is a lightweight, extensible API Gateway for Go applications, designed to handle routing, proxying, and middleware management with ease.
- Simple Configuration: YAML-based setup for quick deployment
- Middleware Architecture: Pre-built middleware for logging, CORS and easy extension points
- Flexible Routing: Route HTTP requests to backend services with custom headers and path mapping
- Docker Support: Ready-to-use container with minimal footprint
- Graceful Shutdown: Clean handling of termination signals
- Go 1.24 or later (for development)
- Docker (optional, for containerized deployment)
# Clone the repository
git clone https://github.com/arthurdotwork/heimdall.git
cd heimdall
# Build the binary
go build -o heimdall ./cmd/heimdall# Pull the image
docker pull ghcr.io/arthurdotwork/heimdall:latest
# Or build locally
docker build -t heimdall:local .Create a config.yaml file based on the provided example:
gateway:
port: 8080
readTimeout: 5s
writeTimeout: 5s
middlewares:
- logger
- cors
endpoints:
- name: MyAPI
path: /api
target: https://api.example.com
method: GET
headers:
X-My-Header:
- CustomValue
allowed_headers:
- X-Request-Id./heimdall --config config.yamldocker run -p 8080:8080 -v $(pwd)/config.yaml:/etc/heimdall/config.yaml ghcr.io/arthurdotwork/heimdall:latestHeimdall's power comes from its middleware architecture. You can register and chain multiple middleware components to customize the gateway's behavior.
Heimdall comes with pre-configured middleware that you can reference in your config:
gateway:
middlewares:
- logger # Log all requests and responses
- cors # Add Cross-Origin Resource Sharing headersCreating your own middleware is straightforward:
- Define your middleware function:
package main
import (
"net/http"
"github.com/arthurdotwork/heimdall"
)
func myCustomMiddleware() heimdall.Middleware {
return heimdall.MiddlewareFunc(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Your custom logic here
w.Header().Set("X-Custom-Header", "CustomValue")
// Continue to the next middleware or handler
next.ServeHTTP(w, r)
})
})
}- Register your middleware in your application:
func main() {
// Register the middleware with a name
err := heimdall.RegisterMiddleware("custom", myCustomMiddleware())
if err != nil {
// Handle error
}
gateway, err := heimdall.New("config.yaml")
if err != nil {
// Handle error
}
// You can also add middleware programmatically
gateway.Use(myCustomMiddleware())
gateway.Start(context.Background())
}- Reference your middleware in the config file:
endpoints:
- name: ProtectedAPI
path: /protected
target: https://api.example.com/protected
method: GET
middlewares:
- custom # Your registered middlewareMiddlewares execute in order, with global middlewares running before endpoint-specific ones:
Request β Global Middlewares β Endpoint Middlewares β Backend Service
# Run all tests
go test ./...
# Run tests with code coverage
go test -cover ./...Heimdall includes a Taskfile for common development tasks:
# Install task if you don't have it
go install github.com/go-task/task/v3/cmd/task@latest
# Run linters
task lint
# Run tests with better formatting
task testgateway:
port: 8080 # Port to listen on
readTimeout: 5s # Timeout for reading requests
writeTimeout: 5s # Timeout for writing responses
shutdownTimeout: 10s # Timeout for graceful shutdown
middlewares: [] # Global middlewares
endpoints:
- name: String # Endpoint name (for logging)
path: /path # URL path to match
target: http://backend # Target backend URL
method: GET # HTTP method to match
headers: {} # Headers to add to proxied requests
allowed_headers: [] # Headers to forward from client requests
middlewares: [] # Endpoint-specific middlewaresContributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.