API Gateway β
YARP-based reverse proxy providing unified entry point for all Vulcan services
Overview β
The Vulcan API Gateway is built on YARP (Yet Another Reverse Proxy), Microsoft's high-performance reverse proxy library for .NET. It serves as the single entry point for all API traffic, routing requests to the appropriate backend microservices.
Tech Stack:
- .NET 10
- YARP reverse proxy
- ASP.NET Core minimal APIs
- Built-in rate limiting
- Health checks aggregation
Port: 8080 (different from microservices which use port 5000)
Architecture β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Clients β
β Web (React) | Mobile (React Native) | External APIs β
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β
β HTTPS
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β API Gateway (Port 8080) β
β ββββββββββββ ββββββββββββββ βββββββββββ ββββββββββββββββ β
β β YARP β β Rate β β Health β β OpenAPI β β
β β Proxy β β Limiting β β Check β β Aggregation β β
β ββββββββββββ ββββββββββββββ βββββββββββ ββββββββββββββββ β
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββΌβββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β Auth Service β β Leads β β Quotation β
β Port: 3000 β β Port: 5000 β β Port: 5000 β
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β β β
ββββββββββββββββββββββββΌβββββββββββββββββββββββ
β
... and 8 more servicesKey Features β
1. Request Routing β
Routes incoming requests to the correct microservice based on URL path.
Route Pattern:
/api/{service-name}/* β http://vulcan-be-{service-name}:5000/*Example Routes:
/api/auth/*βhttp://vulcan-be-auth:3000/*/api/leads/*βhttp://vulcan-be-leads:5000/*/api/quotation/*βhttp://vulcan-be-quotation:5000/*/api/contracts/*βhttp://vulcan-be-contracts:5000/*/api/projects/*βhttp://vulcan-be-projects:5000/*/api/invoicing/*βhttp://vulcan-be-invoicing:5000/*/api/documents/*βhttp://vulcan-be-documents:5000/*/api/ai/*βhttp://vulcan-be-ai:5000/*/api/planning/*βhttp://vulcan-be-planning:5000/*/api/coresetup/*βhttp://vulcan-be-coresetup:5000/*
2. Rate Limiting β
Protects services from abuse with configurable rate limits.
Default Policy:
- Fixed window: 100 requests per minute per IP
- Sliding window: For premium users (future)
- Token bucket: For burst traffic handling
Configuration:
{
"RateLimiting": {
"PermitLimit": 100,
"Window": "00:01:00",
"QueueLimit": 10
}
}3. Health Check Aggregation β
Combines health checks from all microservices into a single endpoint.
Endpoints:
GET /health- Overall system healthGET /health/ready- Readiness probe (Kubernetes)GET /health/live- Liveness probe (Kubernetes)
Response Example:
{
"status": "Healthy",
"totalDuration": "00:00:00.234",
"entries": {
"auth": { "status": "Healthy", "duration": "00:00:00.012" },
"leads": { "status": "Healthy", "duration": "00:00:00.023" },
"quotation": { "status": "Healthy", "duration": "00:00:00.019" },
...
}
}4. OpenAPI Documentation Aggregation β
Combines Swagger/OpenAPI specs from all microservices.
Endpoints:
GET /scalar/v1- Interactive API documentation (Scalar UI)GET /swagger/v1/swagger.json- Aggregated OpenAPI spec
Features:
- Single documentation page for all services
- Try-it-out functionality
- Authentication integration
- Request/response examples
5. Landing Page β
Simple status page showing gateway health and service availability.
Features:
- Service status indicators
- Link to API documentation
- Health check results
- Version information
Configuration β
YARP Routes β
Configured in appsettings.json:
{
"ReverseProxy": {
"Routes": {
"auth-route": {
"ClusterId": "auth-cluster",
"Match": {
"Path": "/api/auth/{**catch-all}"
}
},
"leads-route": {
"ClusterId": "leads-cluster",
"Match": {
"Path": "/api/leads/{**catch-all}"
}
}
// ... more routes
},
"Clusters": {
"auth-cluster": {
"Destinations": {
"auth": {
"Address": "http://vulcan-be-auth:3000"
}
}
},
"leads-cluster": {
"Destinations": {
"leads": {
"Address": "http://vulcan-be-leads:5000"
}
}
}
// ... more clusters
}
}
}Environment Variables β
Development:
ASPNETCORE_ENVIRONMENT=Development
ASPNETCORE_URLS=http://+:8080Production:
ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=http://+:8080
FORWARD_HEADERS_ENABLED=trueAdding a New Microservice β
When adding a new microservice to Vulcan, follow these steps:
Step 1: Add Route Configuration β
Edit appsettings.json:
{
"ReverseProxy": {
"Routes": {
"newservice-route": {
"ClusterId": "newservice-cluster",
"Match": {
"Path": "/api/newservice/{**catch-all}"
}
}
}
}
}Step 2: Add Cluster Configuration β
{
"ReverseProxy": {
"Clusters": {
"newservice-cluster": {
"Destinations": {
"newservice": {
"Address": "http://vulcan-be-newservice:5000"
}
}
}
}
}
}Step 3: Add Health Check β
Edit Program.cs:
builder.Services.AddHealthChecks()
.AddUrlGroup(
new Uri("http://vulcan-be-newservice:5000/health"),
name: "newservice",
timeout: TimeSpan.FromSeconds(5)
);Step 4: Add to OpenAPI Aggregation β
Edit Services/OpenApiAggregatorService.cs:
private static readonly Dictionary<string, string> ServiceEndpoints = new()
{
// ... existing services
{ "newservice", "http://vulcan-be-newservice:5000/swagger/v1/swagger.json" }
};Step 5: Deploy β
# Rebuild gateway
dotnet build src/Vulcan.Gateway
# Update Kubernetes deployment
kubectl rollout restart deployment/vulcan-be-gateway -n vulcan
# Verify routing
curl http://gateway:8080/api/newservice/healthPerformance Characteristics β
Latency β
- Average overhead: <5ms per request
- P50 latency: ~2ms
- P99 latency: ~15ms
- Connection pooling: Enabled for all destinations
Throughput β
- Requests per second: 10,000+ (single instance)
- Concurrent connections: 1,000+
- Max body size: 100MB
Caching β
- Response caching: Disabled by default (microservices handle caching)
- Connection caching: Enabled (HTTP/2)
- DNS caching: Enabled
Security β
Authentication β
Gateway itself doesn't authenticate requestsβit forwards them to microservices which validate JWT tokens.
Flow:
- Client includes
Authorization: Bearer <token>header - Gateway forwards header to microservice
- Microservice validates token and extracts user context
CORS β
Configured to allow requests from:
https://app.vulcan.se(production)https://staging.vulcan.se(staging)http://localhost:5173(local dev)
Configuration:
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy
.WithOrigins(
"https://app.vulcan.se",
"https://staging.vulcan.se",
"http://localhost:5173"
)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});Rate Limiting β
Applied at gateway level before routing to microservices.
Benefits:
- Protects microservices from DDoS
- Fair usage across clients
- Prevents accidental load spikes
Headers β
Forwarded Headers:
X-Forwarded-For- Client IPX-Forwarded-Proto- Original protocol (HTTP/HTTPS)X-Forwarded-Host- Original host
Monitoring & Observability β
Logging β
Structured logging with Serilog:
- Request/response logs
- Routing decisions
- Health check results
- Error logs with stack traces
Log Level:
- Development: Debug
- Production: Information
Metrics β
Exported to Prometheus/Azure Monitor:
- Request count by route
- Request duration by route
- Health check status
- Rate limit rejections
- Error rate
Distributed Tracing β
OpenTelemetry integration (future):
- Trace requests across gateway + microservices
- Identify bottlenecks
- Debug issues in production
Development β
Local Setup β
cd repos/vulcan-be-gateway
# Restore dependencies
dotnet restore
# Run locally
dotnet run --project src/Vulcan.Gateway
# Gateway available at http://localhost:8080Testing Routes β
# Test gateway health
curl http://localhost:8080/health
# Test auth routing
curl http://localhost:8080/api/auth/health
# Test leads routing
curl http://localhost:8080/api/leads/health
# View API docs
open http://localhost:8080/scalar/v1Deployment β
Docker β
# Build image
docker build -t vulcan-be-gateway .
# Run container
docker run -p 8080:8080 vulcan-be-gatewayKubernetes β
apiVersion: apps/v1
kind: Deployment
metadata:
name: vulcan-be-gateway
namespace: vulcan
spec:
replicas: 3
template:
spec:
containers:
- name: gateway
image: registry.vulcan.se/vulcan-be-gateway:latest
ports:
- containerPort: 8080
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Production"
livenessProbe:
httpGet:
path: /health/live
port: 8080
readinessProbe:
httpGet:
path: /health/ready
port: 8080Load Balancing β
Gateway can be horizontally scaled for high availability:
ββββββββββββββββββ
β Load Balancer β
β (Azure LB/NGINX)β
ββββββββββ¬ββββββββ
β
βββββββββββββββΌββββββββββββββ
βΌ βΌ βΌ
ββββββββββ ββββββββββ ββββββββββ
βGateway β βGateway β βGateway β
β #1 β β #2 β β #3 β
ββββββββββ ββββββββββ ββββββββββTroubleshooting β
Gateway Returns 503 β
Cause: Downstream service unavailable
Solution:
- Check health endpoint:
curl http://gateway:8080/health - Check service status:
kubectl get pods -n vulcan - Check service logs:
kubectl logs -n vulcan <pod-name>
Slow Response Times β
Cause: Downstream service slow or timeout too high
Solution:
- Check gateway metrics for P99 latency
- Profile downstream service
- Adjust timeout in YARP config:json
{ "Clusters": { "service-cluster": { "HttpRequest": { "Timeout": "00:00:30" } } } }
Rate Limit Errors (429) β
Cause: Client exceeding rate limit
Solution:
- Increase rate limit for authenticated users
- Implement exponential backoff on client
- Use caching to reduce requests
Future Enhancements β
Planned Features β
- [ ] JWT validation at gateway (optional)
- [ ] Request/response transformation
- [ ] Circuit breaker pattern
- [ ] Advanced caching (Redis)
- [ ] WebSocket support
- [ ] gRPC support
- [ ] API versioning support
- [ ] Request deduplication
- [ ] Response compression
- [ ] Distributed tracing (OpenTelemetry)
