Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,26 @@ gateway/

The gateway is configured via a YAML file (`configs/bff.yml`). See the example configuration for reference.

## Debugging

### Proxy Debug Mode

The gateway includes a debug mode for its reverse proxies, which can be helpful for understanding how requests are being processed and forwarded.

- **Control**: This mode is controlled by the `debugProxy` boolean flag located in the `global` section of the `configs/bff.yml` configuration file.
- **Functionality**: When enabled, the proxies use a `DebugTransport`. This special transport logs details of outgoing requests, including headers and body (if applicable).
- **Performance Impact**: Enabling `DebugTransport` has a significant performance impact due to the detailed logging it performs.
- **Recommendation**: This mode should **only be enabled for debugging purposes**. It is strongly recommended to keep it disabled in production environments or any situation where performance is critical.

To enable proxy debug mode, set `debugProxy: true` in `configs/bff.yml`:

```yaml
global:
policies:
- cors
debugProxy: true # Enable for debugging
```

### Example Configuration

```yaml
Expand Down
1 change: 1 addition & 0 deletions configs/bff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ policyDefinitions:
global:
policies:
- cors
debugProxy: false # Add this line

endpoints:
- path: /proxy
Expand Down
3 changes: 2 additions & 1 deletion internal/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ type Cors struct {
}

type Global struct {
Policies []string `yaml:"policies" json:"policies"`
Policies []string `yaml:"policies" json:"policies"`
DebugProxy bool `yaml:"debugProxy" json:"debugProxy"`
}
8 changes: 6 additions & 2 deletions internal/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ import (
)

// NewReverseProxy creates a new reverse proxy for the given endpoint
func NewReverseProxy(endpoint config.Endpoint) (*httputil.ReverseProxy, error) {
func NewReverseProxy(endpoint config.Endpoint, debugMode bool) (*httputil.ReverseProxy, error) {
targetURL, err := url.Parse(endpoint.Target.URL)
if err != nil {
return nil, err
}

proxy := httputil.NewSingleHostReverseProxy(targetURL)
proxy.Transport = middleware.DebugTransport{}
if debugMode {
proxy.Transport = middleware.DebugTransport{}
} else {
// Use default transport if not in debug mode
}
proxy.Director = CreateDirector(endpoint, targetURL)

return proxy, nil
Expand Down
14 changes: 3 additions & 11 deletions internal/server/handler.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package server

import (
"log"
"net/http"
"net/http/httputil"

"gateway/server/internal/config"
"gateway/server/internal/middleware"
"gateway/server/internal/proxy"
)

// CreateEndpointHandler creates an HTTP handler for a specific endpoint
func CreateEndpointHandler(endpoint config.Endpoint, corsConfig config.Cors, hasCORS bool) http.HandlerFunc {
func CreateEndpointHandler(reverseProxy *httputil.ReverseProxy, corsConfig config.Cors, hasCORS bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Handle CORS headers
if hasCORS {
Expand All @@ -23,14 +22,7 @@ func CreateEndpointHandler(endpoint config.Endpoint, corsConfig config.Cors, has
return
}

// Create and use reverse proxy
reverseProxy, err := proxy.NewReverseProxy(endpoint)
if err != nil {
log.Printf("Failed to create proxy for %s: %v", endpoint.Path, err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}

// Use the pre-created reverse proxy
reverseProxy.ServeHTTP(w, r)
}
}
23 changes: 15 additions & 8 deletions internal/server/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ import (
)

// RegisterRoutes registers all routes based on the configuration
func RegisterRoutes(mux *http.ServeMux, cfg *config.Config) {
for _, endpoint := range cfg.Endpoints {
registerEndpointRoutes(mux, endpoint, cfg)
func (s *Server) RegisterRoutes() {
for _, endpoint := range s.config.Endpoints {
s.registerEndpointRoutes(endpoint)
}
}

func registerEndpointRoutes(mux *http.ServeMux, endpoint config.Endpoint, cfg *config.Config) {
func (s *Server) registerEndpointRoutes(endpoint config.Endpoint) {
// Merge global policies with endpoint policies
allPolicies := append(endpoint.Policies, cfg.Global.Policies...)
allPolicies := append(endpoint.Policies, s.config.Global.Policies...)
policies := utils.ToSet(allPolicies)

// Check for CORS
_, hasCORS := policies["cors"]

methods := endpoint.Methods
if hasCORS {
methods = append(methods, "OPTIONS")
Expand All @@ -34,11 +34,18 @@ func registerEndpointRoutes(mux *http.ServeMux, endpoint config.Endpoint, cfg *c
routePath += "/"
}

// Retrieve the pre-created proxy. If it doesn't exist (e.g., due to creation error), skip this route.
reverseProxy, ok := s.proxies[endpoint.Path]
if !ok {
fmt.Printf("Proxy for path %s not found, skipping route configuration.\n", endpoint.Path)
return
}

for _, method := range methods {
route := method + " " + routePath
handler := CreateEndpointHandler(endpoint, cfg.PolicyDefinitions.CORS, hasCORS)
handler := CreateEndpointHandler(reverseProxy, s.config.PolicyDefinitions.CORS, hasCORS)

mux.HandleFunc(route, handler)
s.mux.HandleFunc(route, handler)
fmt.Printf("Configured Route %v --> %v\n", route, endpoint.Target.URL)
}
}
26 changes: 20 additions & 6 deletions internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,41 @@ package server

import (
"fmt"
"fmt"
"log"
"net/http"
"net/http/httputil"

"gateway/server/internal/config"
"gateway/server/internal/proxy"
)

// Server represents the HTTP server
type Server struct {
config *config.Config
mux *http.ServeMux
config *config.Config
mux *http.ServeMux
proxies map[string]*httputil.ReverseProxy
}

// New creates a new server instance
func New(cfg *config.Config) *Server {
mux := http.NewServeMux()

server := &Server{
config: cfg,
mux: mux,
config: cfg,
mux: mux,
proxies: make(map[string]*httputil.ReverseProxy),
}

for _, endpoint := range cfg.Endpoints {
p, err := proxy.NewReverseProxy(endpoint, cfg.Global.DebugProxy)
if err != nil {
log.Printf("Failed to create proxy for path %s: %v", endpoint.Path, err)
continue // Or handle as fatal
}
server.proxies[endpoint.Path] = p
}

RegisterRoutes(mux, cfg)
server.RegisterRoutes()
return server
}

Expand Down