Skip to content

Commit bf360bb

Browse files
committed
feat(proxy): add fallback response handling in onError hook
1 parent 8da4887 commit bf360bb

File tree

4 files changed

+468
-4
lines changed

4 files changed

+468
-4
lines changed

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ interface ProxyRequestOptions {
179179
res: Response,
180180
body?: ReadableStream | null,
181181
) => void | Promise<void>
182-
onError?: (req: Request, error: Error) => void | Promise<void>
182+
onError?: (
183+
req: Request,
184+
error: Error,
185+
) => void | Promise<void> | Promise<Response>
183186
beforeCircuitBreakerExecution?: (
184187
req: Request,
185188
opts: ProxyRequestOptions,
@@ -547,6 +550,23 @@ proxy(req, undefined, {
547550
})
548551
```
549552

553+
#### Returning Fallback Responses
554+
555+
You can return a fallback response from the `onError` hook by resolving the hook with a `Response` object. This allows you to customize the error response sent to the client.
556+
557+
```typescript
558+
proxy(req, undefined, {
559+
onError: async (req, error) => {
560+
// Log error
561+
console.error("Proxy error:", error)
562+
563+
// Return a fallback response
564+
console.log("Returning fallback response for:", req.url)
565+
return new Response("Fallback response", { status: 200 })
566+
},
567+
})
568+
```
569+
550570
## Performance Tips
551571

552572
1. **URL Caching**: Keep `cacheURLs` enabled (default 100) for better performance

src/proxy.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,9 @@ export class FetchProxy {
166166
currentLogger.logRequestError(req, err, { requestId, executionTime })
167167

168168
// Execute error hooks
169+
let fallbackResponse: Response | void = undefined
169170
if (options.onError) {
170-
await options.onError(req, err)
171+
fallbackResponse = await options.onError(req, err)
171172
}
172173

173174
// Execute circuit breaker completion hooks for failures
@@ -179,12 +180,17 @@ export class FetchProxy {
179180
state: this.circuitBreaker.getState(),
180181
failureCount: this.circuitBreaker.getFailures(),
181182
executionTimeMs: executionTime,
183+
fallbackResponse,
182184
},
183185
options,
184186
)
185187

188+
if (fallbackResponse) {
189+
// If onError provided a fallback response, return it
190+
return fallbackResponse
191+
}
186192
// Return appropriate error response
187-
if (err.message.includes("Circuit breaker is OPEN")) {
193+
else if (err.message.includes("Circuit breaker is OPEN")) {
188194
return new Response("Service Unavailable", { status: 503 })
189195
} else if (
190196
err.message.includes("timeout") ||

src/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ export type AfterCircuitBreakerHook = (
8383
result: CircuitBreakerResult,
8484
) => void | Promise<void>
8585

86-
export type ErrorHook = (req: Request, error: Error) => void | Promise<void>
86+
export type ErrorHook = (
87+
req: Request,
88+
error: Error,
89+
) => void | Promise<void> | Promise<Response>
8790

8891
// Circuit breaker result information
8992
export interface CircuitBreakerResult {
@@ -92,6 +95,7 @@ export interface CircuitBreakerResult {
9295
state: CircuitState
9396
failureCount: number
9497
executionTimeMs: number
98+
fallbackResponse?: Response | void
9599
}
96100

97101
export enum CircuitState {

0 commit comments

Comments
 (0)