Interceptor membungkus eksekusi dari route handler, memungkinkan Anda menjalankan logika sebelum dan sesudah — serta mentransformasi request atau response. Mereka terinspirasi oleh aspect-oriented programming, ideal untuk cross-cutting concerns seperti logging, transformasi response, caching, dan timing.
Struktur: sebelum + sesudah via RxJS
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log("Before handler"); // runs BEFORE the route handler
const now = Date.now();
return next.handle().pipe( // next.handle() = invoke the handler
tap(() => console.log(`After: ${Date.now() - now}ms`)), // runs AFTER
);
}
}
Sebuah interceptor mengimplementasikan intercept(). Kode sebelum next.handle() dijalankan sebelum handler; next.handle() mengembalikan RxJS Observable dari response, dan operator seperti tap/map memungkinkan Anda untuk bertindak pada response setelah handler selesai.
Mentransformasi response (penggunaan umum)
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler) {
return next.handle().pipe(
map(data => ({ success: true, data, timestamp: new Date().toISOString() })),
// wraps EVERY response in a consistent envelope: { success, data, timestamp }
);
}
}
Menggunakan map, sebuah interceptor dapat mengubah bentuk setiap response — misalnya membungkus semua response dalam envelope standar, pola yang sangat umum untuk response API yang konsisten.
Penggunaan powerful lainnya
// caching — return a cached response, skipping the handler entirely
// timeout — fail requests taking too long
return next.handle().pipe(timeout(5000));
// error mapping — transform exceptions
return next.handle().pipe(catchError(err => throwError(() => new BadGatewayException())));
// excluding fields (serialization) — ClassSerializerInterceptor strips @Exclude() fields
Common interceptor uses:
✓ Logging / timing requests (before + after)
✓ Transforming responses (consistent envelopes, field exclusion)
✓ Caching responses
✓ Adding timeouts
✓ Mapping/handling errors
Menerapkan interceptor
@UseInterceptors(LoggingInterceptor) // method or controller level
app.useGlobalInterceptors(new TransformInterceptor()); // global
Interceptor vs middleware vs guard
Middleware → runs BEFORE everything, with raw req/res (can't easily touch the response)
Guard → AUTHORIZATION decision (allow/block) before the handler
Interceptor → wraps the handler — runs BEFORE and AFTER, can TRANSFORM the response
Fitur utama: interceptor dapat menjalankan logika setelah handler dan mentransformasi response — yang tidak dapat dilakukan middleware dan guard dengan bersih.
Mengapa ini penting
Interceptor adalah fitur NestJS yang powerful untuk menangani cross-cutting concerns dengan elegan, dan kemampuan distinguishing mereka — menjalankan logika baik sebelum maupun sesudah handler, dan mentransformasi response — menjadikan mereka alat yang tepat untuk kebutuhan yang tidak dapat diatasi middleware dan guard.
Memahami mereka penting karena banyak requirement umum memetakan secara natural ke interceptor: consistent response formatting (membungkus semua response dalam envelope standar { success, data }), logging/timing (mengukur durasi handler), caching (mengembalikan response yang di-cache), timeout, transformasi error, dan serialisasi (mengecualikan field sensitif).
Mengetahui struktur (Observable next.handle(), dengan tap/map/catchError untuk bertindak sebelum/sesudah), use case umum, dan terutama bagaimana interceptor berbeda dari middleware dan guard (kemampuan untuk membungkus dan mentransformasi response) adalah bagian kunci dari kompetensi arsitektur NestJS.
Interceptor menjaga logika cross-cutting tetap DRY dan terpusat daripada diduplikasi di seluruh handler, menjadikan mereka alat yang sering digunakan dan penting untuk membangun aplikasi NestJS yang clean dan maintainable.
