Proxy Functionality in the Koritsu Framework
This document demonstrates how to use the new proxy functionality with wildcard patterns and handler support.
Overview
The proxy system allows you to:
- Forward requests to external services based on wildcard patterns
- Execute handlers for authentication, logging, or transformation
- Handle multiple wildcards in paths for complex routing
- Configure timeouts, retries, and headers per proxy
- Support all HTTP methods (GET, POST, PUT, DELETE, etc.)
Basic Configuration
import { Api } from "koritsu";
const api = new Api({
environment: "development",
proxy: {
enabled: true,
configs: [
// Simple proxy without handler
{
pattern: "/api/*",
target: "https://external-api.example.com",
},
// Proxy with authentication handler
{
pattern: "/api/protected/*",
target: "https://secure-api.example.com",
handler: async ({ request, params, target }) => {
const token = request.headers.get("authorization");
if (!token) {
return {
proceed: false,
response: new Response("Unauthorized", { status: 401 }),
};
}
return { proceed: true };
},
}),
],
},
});Wildcard Pattern Matching
Wildcards (*) can be used anywhere in the path and extracted as parameters:
// Single wildcard - matches /users/123, /users/admin, etc.
{
pattern: "/users/*",
target: "https://user-service.com",
},
// Multiple wildcards - matches /tenants/acme/services/auth/data
{
pattern: "/tenants/*/services/*/data",
target: "https://multi-tenant.com",
},
// Mixed patterns - matches /api/v1/users/123/posts/456
{
pattern: "/api/v1/users/*/posts/*",
target: "https://content-service.com",
},Handler Functions
Handlers receive request details and can:
- Block requests by returning
proceed: false - Modify headers or target URL
- Perform authentication, logging, rate limiting, etc.
const authHandler = async ({ request, params, target }) => {
// Access extracted parameters from wildcards
const userId = params.param0; // First wildcard value
const postId = params.param1; // Second wildcard value
// Validate authorization
const token = request.headers.get("authorization");
if (!isValidToken(token)) {
return {
proceed: false,
response: new Response(JSON.stringify({ error: "Invalid token" }), {
status: 403,
headers: { "Content-Type": "application/json" },
}),
};
}
// Add custom headers for downstream service
return {
proceed: true,
headers: {
"X-User-ID": userId,
"X-Original-Host": request.headers.get("host"),
},
};
};Advanced Configuration
{
pattern: "/api/external/*",
target: "https://external-service.com",
description: "External API proxy with auth",
handler: authHandler,
timeout: 15000, // 15 second timeout
retries: 3, // Retry failed requests 3 times
logging: true, // Enable proxy logging (default: true)
headers: {
// Additional headers for all requests
"X-API-Gateway": "koritsu",
"X-Version": "1.0",
},
});Controlling Proxy Logging
By default, the proxy logs successful requests, retries, and errors. You can control this behavior using the logging property:
// Enable logging (default behavior)
{
pattern: "/api/verbose/*",
target: "https://api.example.com",
logging: true, // Will log: [INFO] Proxied GET /api/verbose/test -> https://api.example.com/api/verbose/test (200) [attempt 1]
}
// Disable logging for quieter operation
{
pattern: "/api/quiet/*",
target: "https://api.example.com",
logging: false, // No proxy logs will be generated
}When logging is disabled, the proxy will still function normally but won't generate any log messages for:
- Successful proxy requests
- Retry attempts
- Error messages from failed proxy requests
This is useful for:
- High-traffic endpoints: Reduce log noise for frequently accessed APIs
- Health checks: Avoid cluttering logs with routine health check requests
- Development environments: Focus logs on specific proxy configurations
- Production optimization: Reduce logging overhead for performance-critical paths
Note: Disabling proxy logging only affects the proxy-specific log messages. General HTTP request logs and application-level logs are controlled separately.
Dynamic Target Selection
Handlers can change the target URL based on request parameters:
const routingHandler = async ({ request, params, target }) => {
const tenantId = params.param0;
// Route premium tenants to different service
const finalTarget =
tenantId === "premium"
? "https://premium-service.com"
: "https://standard-service.com";
return {
proceed: true,
target: finalTarget,
headers: {
"X-Tenant-ID": tenantId,
},
};
};Auth-Only Endpoints (No Proxying)
You can create proxy configurations that handle requests entirely within the handler without forwarding to an external service by omitting the target field:
{
pattern: "/auth/*",
// No target specified - handled entirely by the handler
description: "Authentication endpoints handled locally",
handler: async ({ request }) => {
const url = new URL(request.url);
if (url.pathname === "/auth/login") {
// Handle login logic
const body = await request.json() as { username?: string; password?: string };
if (body.username === "admin" && body.password === "secret") {
return {
proceed: false, // Don't proxy anywhere
response: new Response(JSON.stringify({
success: true,
token: "jwt-token-here",
user: { id: 1, username: "admin" }
}), {
status: 200,
headers: { "Content-Type": "application/json" }
})
};
} else {
return {
proceed: false,
response: new Response(JSON.stringify({
error: "Invalid credentials"
}), {
status: 401,
headers: { "Content-Type": "application/json" }
})
};
}
}
if (url.pathname === "/auth/validate") {
// Handle token validation
const authHeader = request.headers.get("authorization");
if (!authHeader?.startsWith("Bearer ")) {
return {
proceed: false,
response: new Response(JSON.stringify({
error: "Missing authorization header"
}), {
status: 401,
headers: { "Content-Type": "application/json" }
})
};
}
// Validate token and return user info
return {
proceed: false,
response: new Response(JSON.stringify({
valid: true,
user: { id: 1, username: "admin" }
}), {
status: 200,
headers: { "Content-Type": "application/json" }
})
};
}
// Default 404 for unhandled auth endpoints
return {
proceed: false,
response: new Response(JSON.stringify({
error: "Auth endpoint not found"
}), {
status: 404,
headers: { "Content-Type": "application/json" }
})
};
}
}This pattern is useful for:
- Authentication services: Handle login, logout, token validation locally
- API rate limiting: Block requests without forwarding
- Request validation: Validate and reject malformed requests
- Mock endpoints: Return mock data during development
- Health checks: Respond to health/status requests locally
Error Handling
The proxy system automatically handles:
- Connection failures: Returns 502 Bad Gateway
- Timeouts: Configurable per proxy, returns 502 on timeout
- Retries: Exponential backoff for failed requests
- 404s: Non-matching patterns return 404 Not Found
Integration with File-Based Routes
Proxies are checked before file-based routes, allowing you to:
- Proxy some paths to external services
- Handle others with local route files
- Override specific paths with local implementations
Testing
The framework includes comprehensive tests for:
- Pattern matching with various wildcard combinations
- Handler execution and parameter extraction
- Authentication and authorization flows
- Error handling and timeouts
- Integration with the file-based routing system
Example Use Cases
- API Gateway: Proxy different API versions to different services
- Authentication Layer: Validate tokens before forwarding requests
- Auth-Only Services: Handle authentication endpoints locally without proxying
- Load Balancing: Route requests based on tenant or user type
- Legacy Migration: Gradually migrate endpoints from old to new services
- Rate Limiting: Implement custom rate limiting in handlers
- Request Transformation: Modify headers or request data before forwarding
- Mock Services: Return mock responses during development/testing
- Health Checks: Handle health/status endpoints locally
Performance Considerations
- Proxies are checked in order of specificity (fewer wildcards = higher priority)
- Handlers should be fast to avoid blocking request processing
- Use appropriate timeouts to prevent hanging requests
- Consider retry strategy based on your target service characteristics
Security Notes
- Handlers have access to all request data - handle sensitive information carefully
- Validate all extracted parameters before using them
- Consider implementing rate limiting and request size limits
- Use HTTPS for target URLs when handling sensitive data