A timeout interceptor helps stop a request if it takes too long. This keeps your app fast and avoids waiting forever.
Timeout interceptor in NestJS
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, RequestTimeoutException } from '@nestjs/common'; import { Observable, throwError, TimeoutError } from 'rxjs'; import { timeout, catchError } from 'rxjs/operators'; @Injectable() export class TimeoutInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { return next.handle().pipe( timeout(5000), // time in milliseconds catchError(err => { if (err instanceof TimeoutError) { return throwError(() => new RequestTimeoutException()); } return throwError(() => err); }), ); } }
The timeout operator sets the max wait time in milliseconds.
If the timeout happens, it throws a TimeoutError, which we catch and convert to a NestJS RequestTimeoutException.
timeout(3000) // sets timeout to 3 seconds
timeout(10000) // sets timeout to 10 seconds
catchError(err => {
if (err instanceof TimeoutError) {
return throwError(() => new RequestTimeoutException('Request took too long'));
}
return throwError(() => err);
})This controller has two routes. The fast route responds quickly within the timeout. The slow route takes longer than the 5-second timeout and will cause a timeout error.
import { Controller, Get, UseInterceptors } from '@nestjs/common'; import { Observable, of } from 'rxjs'; import { delay } from 'rxjs/operators'; import { TimeoutInterceptor } from './timeout.interceptor'; @Controller('test') @UseInterceptors(TimeoutInterceptor) export class TestController { @Get('fast') fastResponse(): Observable<string> { return of('Fast response').pipe(delay(1000)); // responds in 1 second } @Get('slow') slowResponse(): Observable<string> { return of('Slow response').pipe(delay(6000)); // responds in 6 seconds } }
Set the timeout value based on your app's needs and expected response times.
Use this interceptor globally or on specific controllers/routes.
Remember to import and provide the interceptor properly in your module.
A timeout interceptor stops requests that take too long.
It uses RxJS timeout and catches errors to send a timeout response.
Use it to keep your app responsive and avoid waiting forever.
Practice
What is the main purpose of a TimeoutInterceptor in a NestJS application?
Solution
Step 1: Understand the role of TimeoutInterceptor
The TimeoutInterceptor is designed to limit how long a request can take before it is stopped.Step 2: Compare options with the interceptor's purpose
Only To stop requests that take too long and prevent hanging. describes stopping long requests to avoid hanging, which matches the interceptor's goal.Final Answer:
To stop requests that take too long and prevent hanging. -> Option AQuick Check:
TimeoutInterceptor stops long requests = D [OK]
- Confusing timeout with logging or caching
- Thinking it handles authentication
- Assuming it speeds up all requests
Which of the following is the correct way to apply a timeout of 5 seconds using RxJS timeout operator inside a NestJS interceptor?
return next.handle().pipe( ... )Solution
Step 1: Understand RxJS timeout parameter
Thetimeoutoperator expects time in milliseconds, so 5 seconds is 5000 ms.Step 2: Match the correct timeout value
Only return next.handle().pipe(timeout(5000)); uses 5000 which equals 5 seconds; others use incorrect values.Final Answer:
return next.handle().pipe(timeout(5000)); -> Option CQuick Check:
Timeout in ms for 5 seconds = 5000 [OK]
- Using seconds instead of milliseconds
- Using too small timeout values
- Forgetting to import timeout operator
Given this TimeoutInterceptor code snippet, what will be the output if the request handler takes 7 seconds to respond?
intercept(context, next) {
return next.handle().pipe(
timeout(5000),
catchError(err => throwError(() => new RequestTimeoutException()))
);
}Solution
Step 1: Analyze timeout duration and handler delay
The timeout is set to 5000 ms (5 seconds), but the handler takes 7 seconds, which is longer.Step 2: Understand error handling on timeout
When timeout triggers, catchError throws a RequestTimeoutException, so the request errors after 5 seconds.Final Answer:
The request throws a RequestTimeoutException after 5 seconds. -> Option BQuick Check:
Handler > timeout triggers RequestTimeoutException = A [OK]
- Assuming request completes despite timeout
- Confusing generic error with RequestTimeoutException
- Ignoring catchError usage
Identify the error in this TimeoutInterceptor implementation:
intercept(context, next) {
return next.handle().pipe(
timeout(3000),
catchError(err => {
throw new RequestTimeoutException();
})
);
}Solution
Step 1: Check error handling inside catchError
InsidecatchError, throwing an error directly breaks the observable chain; it should return an observable error usingthrowError.Step 2: Validate other options
Timeout is correctly in milliseconds, imports are assumed correct, and interceptors return Observables, so only UsingthrowinsidecatchErrorinstead of returning an observable error. is the error.Final Answer:
UsingthrowinsidecatchErrorinstead of returning an observable error. -> Option AQuick Check:
Use throwError() inside catchError, not throw [OK]
- Throwing error directly inside catchError
- Confusing milliseconds with seconds
- Assuming interceptors return Promises
You want to create a TimeoutInterceptor that applies a 3-second timeout globally but allows a specific route to override it with a 10-second timeout. Which approach correctly implements this behavior?
Solution
Step 1: Understand global and route-specific timeout needs
Global interceptor applies 3 seconds by default; specific routes can override by metadata.Step 2: Implement override using custom decorator and metadata
Custom decorator sets timeout metadata on route; interceptor reads it and uses that value if present.Step 3: Evaluate other options
Applying multiple global interceptors causes conflicts; setting longer timeout globally and reducing for most routes reverses the logic; creating separate interceptors without a global one loses timeout protection on other routes.Final Answer:
Use a global TimeoutInterceptor with 3 seconds and a custom decorator to set metadata for 10 seconds, then read metadata inside the interceptor to override timeout. -> Option DQuick Check:
Use metadata + decorator to override global timeout [OK]
- Applying multiple global interceptors causing conflicts
- Hardcoding timeout values without metadata
- Not reading route metadata inside interceptor
Ready to prove it?
Pass the test and this pattern moves unknown
