HttpInterceptor
Interceptors sit between the client and the FetchBackend. Each interceptor receives the request context and a next function, and must return an Observable<HttpEvent>. Interceptors are applied in the order they are registered and can inspect or modify the request before calling next, and inspect or transform the response stream after.
HttpInterceptor interface
Class-based interceptor. Implement intercept and pass an instance in FetchBackend.Options.interceptors.
interface HttpInterceptor<TRequest = HttpBackend.RequestInit> {
intercept(req: TRequest, next: HttpHandler<TRequest>): Observable<HttpEvent>;
}
import { HttpInterceptor, HttpHandler, HttpBackend } from '@opra/client';
import { Observable } from 'rxjs';
export class AuthInterceptor implements HttpInterceptor {
constructor(private readonly getToken: () => string) {}
intercept(req: HttpBackend.RequestInit, next: HttpHandler): Observable<HttpEvent> {
req.headers.set('Authorization', `Bearer ${this.getToken()}`);
return next.handle(req);
}
}
HttpInterceptorFn type
Functional interceptor — a plain function with the same signature. Simpler to write when no class state is needed.
type HttpInterceptorFn<TRequest = HttpBackend.RequestInit> = (
req: TRequest,
next: HttpHandlerFn<TRequest>,
) => Observable<HttpEvent<unknown>>;
import { HttpInterceptorFn } from '@opra/client';
export const loggingInterceptor: HttpInterceptorFn = (req, next) => {
console.log('→', req.method, req.url);
return next(req);
};
HttpHandler / HttpHandlerFn
The next argument passed to class-based interceptors is an HttpHandler:
interface HttpHandler<TRequest = HttpBackend.RequestInit> {
handle(req: TRequest): Observable<HttpEvent>;
}
The next argument passed to functional interceptors is an HttpHandlerFn:
type HttpHandlerFn<TRequest = HttpBackend.RequestInit> =
(req: TRequest) => Observable<HttpEvent>;
Registering interceptors
Pass interceptors in FetchBackend.Options when constructing the client. Duplicates are de-duped automatically.
const client = new OpraHttpClient('https://api.example.com', {
interceptors: [
new AuthInterceptor(() => localStorage.getItem('token') ?? ''),
loggingInterceptor,
],
});
Examples
Add auth token
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpBackend.RequestInit, next: HttpHandler): Observable<HttpEvent> {
req.headers.set('Authorization', `Bearer ${getAccessToken()}`);
return next.handle(req);
}
}
Retry on network errors
import { retry } from 'rxjs';
export const retryInterceptor: HttpInterceptorFn = (req, next) =>
next(req).pipe(retry({ count: 2, delay: 300 }));
Add correlation ID
import { tap } from 'rxjs';
import { HttpEventType } from '@opra/client';
export const correlationInterceptor: HttpInterceptorFn = (req, next) => {
req.headers.set('X-Correlation-Id', crypto.randomUUID());
return next(req).pipe(
tap(event => {
if (event.type === HttpEventType.Response) {
console.log('←', event.response.status);
}
}),
);
};