Architekcie imperium! Architekt Vitruvius, mistrz budowli i systemow, przygotowal dla Ciebie najwazniejsza lekcje tego modulu. Poznales juz middleware, guardy, interceptory, pipes, custom decorators i exception filters. Teraz czas zobaczyc, jak to WSZYSTKO laczy sie w jedna calosc - pelny cykl zycia zadania HTTP w NestJS!
Wyobraz sobie, ze depesza (request HTTP) wyrusza z dalekiej prowincji do Cezara. Po drodze przechodzi przez wiele punktow kontrolnych. Oto dokladna kolejnosc:
1Przychodzace zadanie HTTP
2 |
3 v
4 1. MIDDLEWARE (Straznik bramy)
5 |
6 v
7 2. GUARDS (Kontrola uprawnien)
8 |
9 v
10 3. INTERCEPTORS - before (Kronikarz - poczatek)
11 |
12 v
13 4. PIPES (Kontrola jakosci danych)
14 |
15 v
16 5. ROUTE HANDLER (Cezar podejmuje decyzje)
17 |
18 v
19 6. INTERCEPTORS - after (Kronikarz - koniec)
20 |
21 v
22 7. EXCEPTION FILTERS (Trybunal - w razie bledu)
23 |
24 v
25 Odpowiedz HTTPMiddleware wykonuje sie PIERWSZY, zanim NestJS w ogole wie, ktora metoda kontrolera zostanie wywolana. Ma dostep do surowego obiektu Request i Response:
1// Middleware wykonuje sie jako PIERWSZY
2@Injectable()
3export class LoggerMiddleware implements NestMiddleware {
4 use(req: Request, res: Response, next: NextFunction) {
5 console.log('[1. MIDDLEWARE] Depesza dotarla do bramy');
6 console.log('Metoda: ' + req.method + ', Sciezka: ' + req.path);
7 next(); // Przekaz dalej
8 }
9}Guards wykonuja sie PO middleware, ale PRZED interceptorami i pipe'ami. Ich jedynym zadaniem jest odpowiedziec na pytanie: "Czy ten request ma prawo kontynuowac?":
1// Guard wykonuje sie jako DRUGI
2@Injectable()
3export class AuthGuard implements CanActivate {
4 canActivate(context: ExecutionContext): boolean {
5 console.log('[2. GUARD] Sprawdzam uprawnienia legionisty');
6 const request = context.switchToHttp().getRequest();
7 return !!request.headers.authorization; // true = wpusc, false = zablokuj
8 }
9}Interceptory maja unikalna wlasciwosc - wykonuja sie dwukrotnie: raz PRZED handlerem i raz PO nim. Faza "before" to kod przed
next.handle():1// Interceptor - faza BEFORE (trzeci krok)
2@Injectable()
3export class TimingInterceptor implements NestInterceptor {
4 intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
5 const start = Date.now();
6 console.log('[3. INTERCEPTOR before] Kronikarz rozpoczyna zapis');
7
8 return next.handle().pipe(
9 // Ta czesc to faza AFTER (szosty krok)
10 tap(() => {
11 const duration = Date.now() - start;
12 console.log('[6. INTERCEPTOR after] Czas: ' + duration + 'ms');
13 }),
14 );
15 }
16}Pipes wykonuja sie BEZPOSREDNIO przed handlerem. Transformuja i waliduja dane wejsciowe:
1// Pipe wykonuje sie jako CZWARTY
2@Injectable()
3export class ParseLegionIdPipe implements PipeTransform {
4 transform(value: any) {
5 console.log('[4. PIPE] Waliduje dane wejsciowe: ' + value);
6 const id = parseInt(value, 10);
7 if (isNaN(id)) {
8 throw new BadRequestException('ID musi byc liczba!');
9 }
10 return id;
11 }
12}Handler to docelowa metoda kontrolera - tutaj wykonuje sie logika biznesowa:
1@Controller('legiones')
2export class LegionController {
3 @Get(':id')
4 @UseGuards(AuthGuard)
5 @UseInterceptors(TimingInterceptor)
6 findLegion(@Param('id', ParseLegionIdPipe) id: number) {
7 console.log('[5. HANDLER] Cezar przetwarza zapytanie o legion ' + id);
8 return { id, name: 'Legio X Gemina', commander: 'Marcus' };
9 }
10}Po zakonczeniu handlera, sterowanie wraca do interceptora - do kodu wewnatrz
pipe(tap(...)). Tu mozesz transformowac odpowiedz, logowac czas, itp.Exception Filters wykonuja sie TYLKO gdy zostanie rzucony wyjatek - na dowolnym etapie. Jesli guard rzuci ForbiddenException, filtr to przechwyci. Jesli pipe rzuci BadRequestException - tez:
1// Exception Filter - lapie bledy z KAZDEGO etapu
2@Catch(HttpException)
3export class ImperiumExceptionFilter implements ExceptionFilter {
4 catch(exception: HttpException, host: ArgumentsHost) {
5 console.log('[7. EXCEPTION FILTER] Trybunal obsluguje blad');
6 const ctx = host.switchToHttp();
7 const response = ctx.getResponse();
8 response.status(exception.getStatus()).json({
9 error: exception.message,
10 timestamp: new Date().toISOString(),
11 });
12 }
13}Zrozumienie kolejnosci jest kluczowe dla debugowania:
1// Przyklad: Co sie stanie gdy guard odrzuci request?
2// 1. Middleware - WYKONA SIE (logowanie)
3// 2. Guard - ODRZUCI (rzuci ForbiddenException)
4// 3. Interceptor before - NIE wykona sie
5// 4. Pipe - NIE wykona sie
6// 5. Handler - NIE wykona sie
7// 6. Interceptor after - NIE wykona sie
8// 7. Exception Filter - WYKONA SIE (obsluzy ForbiddenException)
9
10// Przyklad: Co sie stanie gdy pipe odrzuci dane?
11// 1. Middleware - WYKONA SIE
12// 2. Guard - WYKONA SIE (przepusci)
13// 3. Interceptor before - WYKONA SIE
14// 4. Pipe - ODRZUCI (rzuci BadRequestException)
15// 5. Handler - NIE wykona sie
16// 6. Interceptor after - NIE wykona sie (brak odpowiedzi)
17// 7. Exception Filter - WYKONA SIE (obsluzy BadRequestException)Praktyczna technika debugowania - dodaj logi na kazdym etapie:
1// middleware
2console.log('[MW] ' + req.method + ' ' + req.path);
3
4// guard
5console.log('[GUARD] User: ' + request.user?.name);
6
7// interceptor before
8console.log('[INT-B] Handler: ' + context.getHandler().name);
9
10// pipe
11console.log('[PIPE] Value: ' + value + ' -> ' + transformed);
12
13// handler
14console.log('[HANDLER] Processing...');
15
16// interceptor after
17console.log('[INT-A] Duration: ' + duration + 'ms');
18
19// exception filter
20console.log('[FILTER] Error: ' + exception.message);Gdy zobaczysz logi, mozesz dokladnie sledzic droge requestu przez caly pipeline i szybko znalezc, na ktorym etapie wystepuje problem.
Zapamietaj te kolejnosc jak maszerujaca kolumne legionu:
Znajomosc tego cyklu to fundament kazdego zaawansowanego programisty NestJS - jak znajomosc strategii bitewnej dla centuriona!