# 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. - Published: 2026-03-30 - Updated: 2026-05-04 - Author: Anthony Fillion-Maillet - Tags: nestjs, guards, interceptors, architecture, interview - Reading time: 9 min --- 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. > **Mülakatçıların değerlendirdiği şey** > > 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." ```typescript // roles.guard.ts 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('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: ```typescript // roles.decorator.ts 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." ```typescript // logging.interceptor.ts 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 { 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: ```typescript // transform.interceptor.ts 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 { data: T; timestamp: string; path: string; } @Injectable() export class TransformInterceptor implements NestInterceptor> { intercept(context: ExecutionContext, next: CallHandler): Observable> { 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. > **Guard vs Interceptor vs Middleware** > > 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?" ```typescript // orders/orders.module.ts 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: ```typescript // 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. ## 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." ```typescript // cache/cache.module.ts 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: ```typescript // cache/cache.service.ts import { Injectable, Inject } from '@nestjs/common'; import { CacheModuleOptions } from './cache.module'; @Injectable() export class CacheService { private store = new Map(); 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(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. > **Mülakat tuzağı: @Global()** > > 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. ```typescript // auth.decorator.ts 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: ```typescript // orders/orders.controller.ts 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 `CanActivate` ve `Reflector` kullanı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 `forwardRef` ile 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 - `applyDecorators` birden fazla Guard'ı tek, okunabilir bir dekoratörde birleştirir - Bu soruları [NestJS modülleri](/technologies/node-nestjs/interview-questions/nestjs-modules-di) ve [Interceptors](/technologies/node-nestjs/interview-questions/middleware-interceptors) üzerinde gerçek kodla pratik edin --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/node-nestjs/nestjs-guards-interceptors-modular-architecture