Documentation
¶
Index ¶
- func ValidateConfig(cfg *Config) error
- func WriteError(w http.ResponseWriter, code ClientError, status int)
- type AddrList
- type AdminConfig
- type AggregationConfig
- type CircuitBreakerConfig
- type ClientError
- type Config
- type FlowConfig
- type GatewayConfig
- type LoadBalancingConfig
- type MetricsConfig
- type MiddlewareConfig
- type OTLPConfig
- type ObservabilityConfig
- type OnConflictConfig
- type PluginConfig
- type PolicyConfig
- type ProblemDetails
- type RateLimiterConfig
- type RetryConfig
- type Router
- type RouterBundle
- type RoutingConfig
- type RoutingConfigSet
- type ServerConfig
- type ServerTLSConfig
- type ServiceConfig
- type TLSConfig
- type TracingConfig
- type TransportConfig
- type UpstreamConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ValidateConfig ¶ added in v0.8.0
func WriteError ¶
func WriteError(w http.ResponseWriter, code ClientError, status int)
WriteError writes a single-cause RFC 9457 Problem Details response: rate limiting, request-size limits, plugin failures, and any other gateway-side rejection that never reaches an upstream at all.
Types ¶
type AdminConfig ¶
type AdminConfig struct {
Port int `yaml:"port" validate:"required,min=1,max=65535"`
BindAddr string `yaml:"bind_addr" default:"127.0.0.1"`
Timeout time.Duration `yaml:"timeout" default:"5m"`
HeaderTimeout time.Duration `yaml:"header_timeout" default:"5s"`
EnablePprof bool `yaml:"enable_pprof" default:"false"`
}
type AggregationConfig ¶
type AggregationConfig struct {
BestEffort bool `yaml:"best_effort"`
Strategy string `yaml:"strategy" validate:"required,oneof=array merge namespace"`
OnConflict *OnConflictConfig `yaml:"on_conflict" validate:"required_if=Strategy merge"`
}
type CircuitBreakerConfig ¶
type ClientError ¶
type ClientError string
const ( ClientErrRateLimitExceeded ClientError = "RATE_LIMIT_EXCEEDED" ClientErrPayloadTooLarge ClientError = "PAYLOAD_TOO_LARGE" ClientErrUpstreamBodyTooLarge ClientError = "UPSTREAM_BODY_TOO_LARGE" ClientErrUpstreamError ClientError = "UPSTREAM_ERROR" ClientErrUpstreamClientError ClientError = "UPSTREAM_CLIENT_ERROR" ClientErrUpstreamRedirect ClientError = "UPSTREAM_REDIRECT" ClientErrUpstreamMalformed ClientError = "UPSTREAM_MALFORMED" ClientErrInternal ClientError = "INTERNAL" ClientErrAborted ClientError = "ABORTED" ClientErrValueConflict ClientError = "VALUE_CONFLICT" )
func (ClientError) String ¶
func (err ClientError) String() string
type Config ¶
type Config struct {
Schema string `yaml:"schema" validate:"required,oneof=v1"`
Debug bool `yaml:"debug"`
Gateway GatewayConfig `yaml:"gateway" validate:"required"`
}
func LoadConfig ¶
LoadConfig reads, parses, applies defaults, validates, and returns the config.
type FlowConfig ¶
type FlowConfig struct {
Path string `yaml:"path" validate:"required,startswith=/"`
Method string `yaml:"method" validate:"required,oneof=GET POST PUT PATCH DELETE HEAD OPTIONS QUERY"`
Streaming bool `yaml:"streaming"`
// Aggregation is required only for flows with more than one upstream -
// a single-upstream flow is proxied directly and never aggregates
// (enforced in validateFlows, since that depends on len(Upstreams)).
Aggregation *AggregationConfig `yaml:"aggregation"`
Upstreams []UpstreamConfig `yaml:"upstreams" validate:"required,min=1,dive,required"`
Plugins []PluginConfig `yaml:"plugins" validate:"omitempty,dive"`
Middlewares []MiddlewareConfig `yaml:"middlewares" validate:"omitempty,dive"`
}
type GatewayConfig ¶
type GatewayConfig struct {
Service ServiceConfig `yaml:"service"`
Server ServerConfig `yaml:"server" validate:"required"`
Admin AdminConfig `yaml:"admin" validate:"required"`
Observability ObservabilityConfig `yaml:"observability"`
Routing RoutingConfig `yaml:"routing" validate:"required"`
}
type LoadBalancingConfig ¶
type LoadBalancingConfig struct {
Mode string `yaml:"mode"`
}
type MetricsConfig ¶
type MetricsConfig struct {
Enabled bool `yaml:"enabled"`
Exporter string `yaml:"exporter" validate:"required_if=Enabled true,omitempty,oneof=otlp prometheus"`
OTLP OTLPConfig `yaml:"otlp"`
}
type MiddlewareConfig ¶
type OTLPConfig ¶
type ObservabilityConfig ¶
type ObservabilityConfig struct {
Tracing TracingConfig `yaml:"tracing"`
Metrics MetricsConfig `yaml:"metrics"`
}
type OnConflictConfig ¶
type PluginConfig ¶
type PolicyConfig ¶
type PolicyConfig struct {
HeaderBlacklist []string `yaml:"header_blacklist"`
RequireBody bool `yaml:"require_body"`
MaxResponseBodySize int64 `yaml:"max_response_body_size"`
FollowRedirects bool `yaml:"follow_redirects"`
RetryConfig RetryConfig `yaml:"retry"`
CircuitBreakerConfig CircuitBreakerConfig `yaml:"circuit_breaker"`
LoadBalancingConfig LoadBalancingConfig `yaml:"load_balancing"`
}
type ProblemDetails ¶ added in v0.10.0
type ProblemDetails struct {
// Type is always "about:blank" (RFC 9457 §4.2's own default for "no
// further-specific type"): it is never a dereferencable URI on purpose.
// A real one - even a stable, non-existent one under the gateway's own
// docs domain - names the software fronting this upstreams to anyone
// who receives an error, which is itself reconnaissance: it tells a
// caller they're behind an aggregating gateway and invites probing for
// what that implies about the backend topology. Errors carries the
// actual discriminator instead - a closed, generic enum that says
// nothing about what's behind the gateway.
Type string `json:"type"`
Title string `json:"title"`
Status int `json:"status"`
Detail string `json:"detail,omitempty"`
// Errors lists every distinct underlying ClientError - always at least
// one. This is the one machine-readable discriminator (Type is constant,
// see above); Title is for humans and may change wording over time.
// More than one entry only for a multi-upstream flow where several
// upstreams failed differently. This is a problem type extension member
// (RFC 9457 §3.2), not a spec violation.
Errors []ClientError `json:"errors"`
}
ProblemDetails is the RFC 9457 ("Problem Details for HTTP APIs") body used for every gateway-authored response that carries no upstream data of its own - rate limiting, payload limits, plugin failures, and upstream/gateway failures that never produced anything worth returning as data.
A response that *does* carry data (a full or partial aggregation success) is never wrapped: the body is the aggregated payload itself, exactly as a client of the upstream(s) directly would see it. See Router.buildResponse.
type RateLimiterConfig ¶
type RetryConfig ¶
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
func (*Router) ServeHTTP ¶
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
ServeHTTP handles incoming HTTP requests through the full router pipeline:
- Rate limiting - rejects requests exceeding the configured limit.
- Flow matching - chi router finds the flow by method and path (404 if none).
- Middleware execution - per-flow middlewares wrap the handler.
- Request plugins - run before the upstream call; may modify the request.
- Upstream dispatch - a streaming flow is piped through unbuffered (handleStreaming); a single-upstream flow is called directly and its status/headers/body are proxied as-is (buildProxyResponse); a multi-upstream flow fans out and aggregates (merge/array/namespace, with bestEffort support).
- Response plugins - run after dispatch; may modify headers or body.
- Response writing - status, headers, and body sent to the client.
A single-upstream flow forwards the upstream's own status/body verbatim on success or on a client error/redirect. A multi-upstream flow's success or partial-success (206, bestEffort) body is the aggregated data itself, with no gateway-added wrapper - a client never has to unwrap a response to get at the payload. Only a response with no data at all (a hard failure with nothing to aggregate, a rejected request that never reached an upstream) is a body, and that body is an RFC 9457 Problem Details document (application/problem+json), not a bespoke shape. Status codes: 200 on full success, 206 on partial, 502/500 on failure.
type RouterBundle ¶
type RouterBundle struct {
Router *Router
TLSRegistry *tlsutil.Registry
MeterProvider otelcommon.Provider
TracerProvider otelcommon.Provider
PromRegistry *prometheus.Registry // nil unless metrics.exporter == "prometheus"
}
func NewRouter ¶
func NewRouter(ctx context.Context, cfgSet RoutingConfigSet, log *zap.Logger) (RouterBundle, error)
type RoutingConfig ¶
type RoutingConfig struct {
RateLimiter RateLimiterConfig `yaml:"rate_limiter" validate:"omitempty"`
TrustedProxies []string `yaml:"trusted_proxies"`
Flows []FlowConfig `yaml:"flows" validate:"min=1,dive,required"`
}
type RoutingConfigSet ¶
type RoutingConfigSet struct {
Routing RoutingConfig
Service ServiceConfig
ServiceVersion string // injected via ldflags
Metrics MetricsConfig
Tracing TracingConfig
}
type ServerConfig ¶
type ServerTLSConfig ¶
type ServerTLSConfig struct {
Enabled bool `yaml:"enabled"`
CertFile string `yaml:"cert_file" validate:"required_if=Enabled true"`
KeyFile string `yaml:"key_file" validate:"required_if=Enabled true"`
MinVersion string `yaml:"min_version" default:"1.2" validate:"omitempty,oneof=1.2 1.3"`
ClientAuth string `yaml:"client_auth" default:"none" validate:"omitempty,oneof=require optional none"`
ClientCAFile string `yaml:"client_ca_file" validate:"required_unless=ClientAuth none"`
}
type ServiceConfig ¶
type ServiceConfig struct {
Name string `yaml:"name" default:"aastro"`
}
type TLSConfig ¶
type TLSConfig struct {
Enabled bool `yaml:"enabled"`
CertFile string `yaml:"cert_file" validate:"required_with=KeyFile"`
KeyFile string `yaml:"key_file" validate:"required_with=CertFile"`
CAFile string `yaml:"ca_file"`
ServerName string `yaml:"server_name"`
InsecureSkipVerify bool `yaml:"insecure_skip_verify"`
MinVersion string `yaml:"min_version" default:"1.2" validate:"omitempty,oneof=1.2 1.3"`
}
type TracingConfig ¶
type TracingConfig struct {
Enabled bool `yaml:"enabled"`
Exporter string `yaml:"exporter" validate:"required_if=Enabled true,omitempty,oneof=otlp"`
SamplingRatio float64 `yaml:"sampling_ratio" default:"1.0" validate:"min=0,max=1"`
OTLP OTLPConfig `yaml:"otlp"`
}
type TransportConfig ¶
type UpstreamConfig ¶
type UpstreamConfig struct {
Name string `yaml:"name" validate:"required"`
Hosts AddrList `yaml:"hosts" validate:"min=1,dive"`
Path string `yaml:"path"`
Method string `yaml:"method"`
Timeout time.Duration `yaml:"timeout" default:"3s"`
ForwardHeaders []string `yaml:"forward_headers"`
ForwardQueries []string `yaml:"forward_queries"`
ForwardParams []string `yaml:"forward_params"`
Policy PolicyConfig `yaml:"policy"`
Transport TransportConfig `yaml:"transport"`
TLS TLSConfig `yaml:"tls"`
}
func DefaultUpstreamConfig ¶ added in v0.8.0
func DefaultUpstreamConfig() UpstreamConfig
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
builtin
|
|
|
middlewares/auth
command
|
|
|
middlewares/compressor
command
|
|
|
middlewares/cors
command
|
|
|
middlewares/logger
command
|
|
|
middlewares/recoverer
command
|
|
|
plugins/camelify
command
|
|
|
plugins/masker
command
|
|
|
plugins/snakeify
command
|
|
|
cmd
|
|
|
aastro
command
|
|
|
aastroctl
command
|
|
|
internal
|
|
|
openapi
Package openapi generates OpenAPI 3.x documents from an aastro gateway configuration.
|
Package openapi generates OpenAPI 3.x documents from an aastro gateway configuration. |
|
otelcommon
Package otelcommon builds the shared OpenTelemetry Resource used by both the metric and tracing providers, so signals from the same process share a consistent identity (service.name, service.version, host, process, …) in the observability backend.
|
Package otelcommon builds the shared OpenTelemetry Resource used by both the metric and tracing providers, so signals from the same process share a consistent identity (service.name, service.version, host, process, …) in the observability backend. |
|
testutil/certgen
Package certgen provides in-process certificate generation and TLS probes for tests.
|
Package certgen provides in-process certificate generation and TLS probes for tests. |