W systemie NestJS, filtry wyjątków pełnią kluczową rolę, umożliwiając przechwytywanie i zarządzanie błędami na poziomie globalnym lub w obrębie konkretnych kontrolerów.
Dzięki nim możliwe jest scentralizowanie logiki zarządzania błędami, ustalenie jednolitego formatu odpowiedzi w przypadku wystąpienia błędów oraz zapewnienie spójności w obsłudze błędów w całej strukturze aplikacji. Zrozumienie działania i wykorzystania filtrów wyjątków jest fundamentalne dla efektywnego zarządzania błędami w twojej aplikacji.
Standardowa obsługa błędów w NestJS
NestJS domyślnie oferuje mechanizm obsługi wyjątków, który interweniuje w przypadku błędów, które nie zostały obsłużone przez kod aplikacji.
Gdy w aplikacji pojawi się nieobsłużony błąd, NestJS przejmuje kontrolę i przekazuje do klienta odpowiedź z kodem błędu serwera wewnętrznego 500. Standardowy format odpowiedzi JSON w takiej sytuacji wygląda następująco:
{ "statusCode": 500, "message": "Internal server error" }
Jeżeli obiekt błędu, zgłoszony przez Twój kod, zawiera pola `statusCode` i `message`, NestJS wykorzysta te wartości, zamiast prezentować domyślną odpowiedź.
Aby uniknąć prezentowania standardowego komunikatu o błędzie i dostarczyć klientowi bardziej zrozumiałą odpowiedź, konieczne jest odpowiednie zdefiniowanie obsługi potencjalnych błędów w aplikacji. Można to zrobić, korzystając z wbudowanych lub niestandardowych filtrów wyjątków w NestJS.
Tworzenie spersonalizowanego filtra wyjątków
Aby zademonstrować proces tworzenia filtra wyjątków, spróbujemy zbudować filtr, który będzie obsługiwał wszystkie wyjątki HTTP.
Rozpocznijmy od utworzenia pliku o nazwie `http.exception.ts` i dodania do niego poniższych importów:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, } from '@nestjs/common'; import { Request, Response } from 'express';
Każdy z importów pełni określoną funkcję:
- `ExceptionFilter`: Jest to interfejs określający strukturę filtra wyjątków.
- `Catch`: To dekorator, który identyfikuje klasę jako filtr wyjątków NestJS.
- `ArgumentsHost`: Ten interfejs pozwala na pobranie argumentów przekazanych do obsługi zdarzenia. Pozwala na wybranie odpowiedniego kontekstu (np. HTTP, RPC czy WebSockets), z którego mają zostać pobrane argumenty.
- `HttpException`: Klasa definiująca podstawowy wyjątek HTTP w NestJS.
- `Request` i `Response`: Interfejsy obiektów żądania i odpowiedzi z Express.js.
Następnie, stwórz klasę `HttpExceptionFilter`, która będzie implementować interfejs `ExceptionFilter`. Dodaj dekorator `Catch`, aby zasygnalizować, że klasa obsługuje wyjątki typu `HttpException`:
@Catch(HttpException) export class HttpExceptionFilter implements ExceptionFilter {}
Wypełnij klasę następującym kodem:
catch(exception: HttpException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const request = ctx.getRequest<Request>(); const status = exception.getStatus(); response.status(status).json({ statusCode: status, timestamp: new Date().toISOString(), path: request.url, message: exception.message || exception.getResponse()['message'] || 'Internal Server Error', }); }
Powyższy kod pobiera obiekty żądania i odpowiedzi z `ArgumentsHost` i wyciąga szczegółowe informacje z obiektu wyjątku. Zwraca klientowi odpowiedź w formacie JSON, która zawiera szczegółowe dane na temat błędu.
Wiązanie filtrów wyjątków
Filtr wyjątków można powiązać z konkretnym kontrolerem lub z całą aplikacją, w zależności od potrzeb.
Aby powiązać filtr wyjątków globalnie, zaimportuj go do pliku `main.ts`. Następnie przekaż instancję filtra do metody `app.useGlobalFilters`:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { HttpExceptionFilter } from './exception/http.exception'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalFilters(new HttpExceptionFilter()); await app.listen(4050); } bootstrap();
Aby powiązać filtr wyjątków z konkretnym kontrolerem, zaimportuj dekorator `UseFilters` oraz sam filtr. Dodaj dekorator `@UseFilters` do klasy kontrolera, przekazując instancję filtra jako argument:
@Controller() @UseFilters(new HttpExceptionFilter()) export class AppController {}
Zakres obsługi błędów zależy od miejsca powiązania filtra. Filtry powiązane z kontrolerem będą obsługiwały tylko błędy w tym kontrolerze, natomiast filtry powiązane globalnie, będą obsługiwały błędy w całej aplikacji.
Wykorzystanie wbudowanych wyjątków do zgłaszania błędów
NestJS udostępnia zestaw wbudowanych klas wyjątków, które można wykorzystać do zgłaszania błędów.
Przykładowo, do zgłaszania błędów z kodem statusu 404, można użyć klasy `NotFoundException`:
getUserById(id: number) { const user = users.find((user) => user.id === id); if (!user) { throw new NotFoundException({ message: `User with id ${id} not found`, }); } }
Powyższy kod używa instrukcji warunkowej do sprawdzenia, czy użytkownik o podanym `id` istnieje. Jeśli nie, generowany jest błąd 404 za pomocą wyjątku `NotFoundException`, do którego jako argument przekazywana jest wiadomość z informacją o błędzie.
Najczęściej wykorzystywane wbudowane klasy wyjątków
Wśród innych wbudowanych klas wyjątków znajdują się między innymi:
- `BadRequestException`: Generuje wyjątek sygnalizujący nieprawidłowe żądanie z kodem stanu 400. Używany, gdy żądanie klienta jest niepoprawne lub źle sformułowane.
- `UnauthorizedException`: Generuje wyjątek sygnalizujący nieautoryzowany dostęp z kodem stanu 401. Używany, gdy użytkownik nie jest uwierzytelniony lub nie ma uprawnień dostępu do zasobu.
- `ForbiddenException`: Generuje wyjątek sygnalizujący zabroniony dostęp z kodem stanu 403. Używany, gdy użytkownik jest uwierzytelniony, ale nie ma uprawnień do wykonania konkretnej operacji.
- `RequestTimeoutException`: Generuje wyjątek sygnalizujący przekroczenie czasu żądania z kodem stanu 408. Używany, gdy serwer przerywa przetwarzanie żądania, ponieważ trwało ono zbyt długo.
- `ConfliktException`: Generuje wyjątek sygnalizujący konflikt z kodem stanu 409. Używany, gdy żądanie klienta jest niezgodne z obecnym stanem zasobu (np. próba utworzenia istniejącego zasobu).
- `InternalServerErrorException`: Generuje wyjątek sygnalizujący wewnętrzny błąd serwera z kodem stanu 500. Używany, gdy po stronie serwera wystąpił nieprzewidziany błąd.
Dobre praktyki obsługi błędów w NestJS
Podczas obsługi błędów w NestJS należy wykorzystywać filtry wyjątków do przechwytywania i obsługi wyjątków na poziomie globalnym lub w obrębie kontrolerów. Dodatkowo warto tworzyć spersonalizowane filtry do obsługi konkretnych typów wyjątków.
Ponadto, ważne jest, aby wykorzystywać odpowiednie wbudowane klasy wyjątków do zgłaszania trafnych i czytelnych błędów. Stosowanie tych praktyk znacznie podnosi niezawodność aplikacji NestJS.
newsblog.pl
Maciej – redaktor, pasjonat technologii i samozwańczy pogromca błędów w systemie Windows. Zna Linuxa lepiej niż własną lodówkę, a kawa to jego główne źródło zasilania. Pisze, testuje, naprawia – i czasem nawet wyłącza i włącza ponownie. W wolnych chwilach udaje, że odpoczywa, ale i tak kończy z laptopem na kolanach.