NestJS Mülakatı: Guards, Interceptors ve Modüler Mimari
Guards, Interceptors ve modüler mimari hakkında NestJS teknik mülakatlarında sıkça sorulan sorular, somut TypeScript kod örnekleri ve teknik açıklamalarla.

NestJS teknik mülakatları her zaman framework'ün üç temel sütununa odaklanır: Guards, Interceptors ve modüler mimari. Bu mekanizmalar, iyi yapılandırılmış her NestJS uygulamasının omurgasını oluşturur ve işe alım yöneticileri framework'e gerçek hakimiyeti değerlendirmek için bunları kullanır.
Guard erişimi kontrol eder (kim girer), Interceptor veriyi dönüştürür (ne girer ve ne çıkar), modüler mimari ise her şeyi düzenler. Üçüne de hakim olmak temel CRUD işlemlerinin ötesinde derin bir NestJS anlayışını gösterir.
NestJS Guards nasıl çalışır ve sık karşılaşılan mülakat senaryoları
Guards, CanActivate arayüzünü uygular ve bir isteğin handler'a ulaşıp ulaşmayacağını belirler. Middleware'den farklı olarak Guards, NestJS yürütme bağlamına (ExecutionContext) erişerek handler metaverilerine dayalı yetkilendirme kararları almayı mümkün kılar.
Klasik soru: "Kullanıcı rollerini doğrulayan bir Guard yazın."
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
// Retrieve roles defined via the @Roles() decorator
const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [
context.getHandler(),
context.getClass(),
]);
// No roles required means the route is public
if (!requiredRoles) return true;
// Extract user from the HTTP request
const { user } = context.switchToHttp().getRequest();
// Check if the user holds at least one required role
return requiredRoles.some((role) => user.roles?.includes(role));
}
}Reflector, özel dekoratörler tarafından eklenen metaverileri okur. Eşlik eden @Roles() dekoratörü şu şekildedir:
import { SetMetadata } from '@nestjs/common';
// Creates a decorator that attaches roles as metadata
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);Güçlü bir mülakat cevabı koddan fazlasını içerir. Yürütme sırası önemlidir: Middleware → Guards → Interceptors (öncesi) → Pipes → Handler → Interceptors (sonrası) → Exception Filters. Bu sıralama neredeyse her NestJS mülakatında karşımıza çıkar.
NestJS Interceptors: istek ve yanıtları dönüştürme
Interceptors, NestInterceptor'ı uygular ve handler öncesinde ve sonrasında veri akışını manipüle etmek için RxJS kullanır. Güçlerini, yürütme hattını temsil eden CallHandler'a erişimden alırlar.
Sık sorulan soru: "Yürütme süresini ölçen bir logging Interceptor'ı oluşturun."
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, Logger } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
private readonly logger = new Logger(LoggingInterceptor.name);
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const { method, url } = request;
const now = Date.now();
// next.handle() invokes the route handler
return next.handle().pipe(
tap(() => {
// Runs AFTER the handler responds
const duration = Date.now() - now;
this.logger.log(`${method} ${url} — ${duration}ms`);
}),
);
}
}RxJS'in tap operatörü, akışı değiştirmeden gözlemler. Yanıtı dönüştürmek için doğru operatör map'tir:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
// Generic interface for a standardized API response
interface ApiResponse<T> {
data: T;
timestamp: string;
path: string;
}
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, ApiResponse<T>> {
intercept(context: ExecutionContext, next: CallHandler): Observable<ApiResponse<T>> {
const request = context.switchToHttp().getRequest();
return next.handle().pipe(
map((data) => ({
data,
timestamp: new Date().toISOString(),
path: request.url,
})),
);
}
}Bu standart yanıt deseni mülakatlarda iyi puan toplar: API tasarımı ve yanıt tutarlılığı üzerine düşünme yeteneğini gösterir.
Middleware: ham HTTP işleme (Express gibi). Guard: erişim için boolean karar. Interceptor: RxJS ile istek/yanıt akışının dönüştürülmesi. Bu üç kavramı mülakatta karıştırmak anlık bir kırmızı bayraktır.
NestJS modüler mimarisi: ölçeklenebilir uygulamalar inşa etmek
Modüler mimari, mülakatlarda junior'ları senior'lardan ayırır. NestJS modül tabanlı bir organizasyon dayatır, ancak gerçek sorular mimari kararları hedef alır: ne zaman modül oluşturulur ve modüller arası bağımlılıklar nasıl yönetilir.
İleri seviye soru: "Doğru şekilde ayrıştırılmış modüllerle bir NestJS e-ticaret uygulamasını nasıl yapılandırırsınız?"
import { Module } from '@nestjs/common';
import { OrdersService } from './orders.service';
import { OrdersController } from './orders.controller';
import { PaymentsModule } from '../payments/payments.module';
import { ProductsModule } from '../products/products.module';
@Module({
// Import modules that OrdersModule depends on
imports: [PaymentsModule, ProductsModule],
controllers: [OrdersController],
providers: [OrdersService],
// Expose OrdersService to modules that import OrdersModule
exports: [OrdersService],
})
export class OrdersModule {}Klasik mülakat tuzağı: döngüsel bağımlılıklar. OrdersModule, PaymentsModule'ü ve PaymentsModule da OrdersModule'ü içe aktarırsa, NestJS başlangıçta hata verir. Acil çıkış forwardRef kullanır:
// Resolving circular dependencies
@Module({
imports: [forwardRef(() => PaymentsModule)],
})
export class OrdersModule {}En güçlü mülakat cevabı, forwardRef'in bir geçici çözüm olduğunu, gerçek bir çözüm olmadığını açıklar. Doğru düzeltme, paylaşılan bir modül (SharedOrderPaymentModule) çıkarmak için yeniden düzenlemek veya iletişimi ayrıştırmak için Event Emitter kullanmaktır.
Node.js / NestJS mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
Dynamic Modules ve gelişmiş yapılandırma
Dynamic Modules, projeler arasında yeniden kullanılabilir, yapılandırılabilir modüller oluşturur. Bu desen senior seviye mülakatlarda görülür.
Soru: "Dinamik seçeneklerle yapılandırılabilir bir cache modülü oluşturun."
import { Module, DynamicModule, Global } from '@nestjs/common';
import { CacheService } from './cache.service';
// Module configuration interface
export interface CacheModuleOptions {
ttl: number; // Time-to-live in seconds
maxItems: number; // Maximum number of entries
prefix: string; // Key prefix
}
@Global() // Available everywhere without explicit import
@Module({})
export class CacheModule {
static forRoot(options: CacheModuleOptions): DynamicModule {
return {
module: CacheModule,
providers: [
{
// Inject options via a custom token
provide: 'CACHE_OPTIONS',
useValue: options,
},
CacheService,
],
exports: [CacheService],
};
}
}İlgili servis seçenekleri @Inject() ile enjekte eder:
import { Injectable, Inject } from '@nestjs/common';
import { CacheModuleOptions } from './cache.module';
@Injectable()
export class CacheService {
private store = new Map<string, { value: any; expiry: number }>();
constructor(@Inject('CACHE_OPTIONS') private options: CacheModuleOptions) {}
set(key: string, value: any): void {
const prefixedKey = `${this.options.prefix}:${key}`;
this.store.set(prefixedKey, {
value,
expiry: Date.now() + this.options.ttl * 1000,
});
}
get<T>(key: string): T | null {
const prefixedKey = `${this.options.prefix}:${key}`;
const entry = this.store.get(prefixedKey);
// Check expiration before returning
if (!entry || entry.expiry < Date.now()) return null;
return entry.value as T;
}
}forRoot / forRootAsync deseni bir NestJS klasiğidir. forRootAsync, yapılandırmayı enjekte edilebilir bir ConfigService'ten yükler ve bu üretim için önerilen uygulamadır.
Bir modülü @Global() olarak işaretlemek pratik görünür, ancak bunu aşırı kullanmak görünmez bağlantılar yaratır. Mülakatta @Global()'ın yatay servisler için (config, cache, logger) ayrılması gerektiğini belirtmek mimari olgunluğu gösterir.
Özel dekoratörler ve Guard kompozisyonu
Özel dekoratörler birden fazla Guard'ı ve metaveriyi tek bir notasyonda birleştirir. Bu konu mid-senior pozisyonlarda ortaya çıkar.
import { applyDecorators, UseGuards, SetMetadata } from '@nestjs/common';
import { JwtAuthGuard } from './jwt-auth.guard';
import { RolesGuard } from './roles.guard';
// Combines JWT authentication + role verification
export function Auth(...roles: string[]) {
return applyDecorators(
SetMetadata('roles', roles),
UseGuards(JwtAuthGuard, RolesGuard),
);
}Bir controller'da kullanım:
import { Controller, Get, Post, Body } from '@nestjs/common';
import { Auth } from '../auth/auth.decorator';
import { OrdersService } from './orders.service';
@Controller('orders')
export class OrdersController {
constructor(private ordersService: OrdersService) {}
@Get()
@Auth('admin', 'manager') // Single decorator replaces UseGuards + Roles
findAll() {
return this.ordersService.findAll();
}
@Post()
@Auth('admin')
create(@Body() dto: CreateOrderDto) {
return this.ordersService.create(dto);
}
}applyDecorators deseni controller kodunu basitleştirir ve yetkilendirme mantığını merkezileştirir. Bu yaklaşımı bir mülakatta proaktif olarak önermek güçlü bir sinyaldir.
Sonuç
- Guards, handler metaverilerine dayalı erişim kararları için
CanActivateveReflectorkullanır - Interceptors, akışı handler öncesinde ve sonrasında dönüştürmek için RxJS'i (
tap,map) kullanır - Yürütme sırası Middleware → Guards → Interceptors → Pipes → Handler neredeyse evrensel bir sorudur
- Döngüsel bağımlılıklar
forwardRefile değil, mimari yeniden düzenleme ile çözülmelidir - Dynamic Modules (
forRoot/forRootAsync) yeniden kullanılabilir bileşenler inşa etme yeteneğini gösterir applyDecoratorsbirden fazla Guard'ı tek, okunabilir bir dekoratörde birleştirir- Bu soruları NestJS modülleri ve Interceptors üzerinde gerçek kodla pratik edin
Pratik yapmaya başla!
Mülakat simülatörleri ve teknik testlerle bilgini test et.
Etiketler
Paylaş
İlgili makaleler

NestJS + Prisma: Node.js için modern backend yığını
NestJS ve Prisma ile modern bir backend API'si oluşturmak için kapsamlı rehber. Kurulum, modeller, servisler, transaction'lar ve en iyi uygulamalar.

Node.js Backend Mülakat Soruları: Kapsamlı Rehber 2026
Node.js backend mülakatlarında en sık sorulan 25 soru. Event loop, async/await, stream, kümeleme ve performans konuları detaylı cevaplarla açıklanmaktadır.

NestJS: Eksiksiz bir REST API Oluşturma
NestJS ile profesyonel bir REST API oluşturmak için kapsamlı rehber. Controller, Service, Module yapıları, class-validator ile doğrulama ve hata yönetimi pratik örneklerle açıklanmaktadır.