# Exception filters

## Exception filters

Nest에는 애플리케이션에서 처리되지 않은 모든 예외를 처리하는 내장 **예외 레이어**가 제공됩니다. 응용 프로그램 코드에서 예외를 처리하지 않으면이 계층에서 예외를 포착하여 적절한 사용자 친화적인 응답을 자동으로 보냅니다.

![](https://docs.nestjs.com/assets/Filter_1.png)

기본적으로 이 동작은 내장 된 **전역 예외 필터**에 의해 수행되는데, 이 예외는 `HttpException` 유형 (및 그 하위 클래스)의 예외를 처리합니다. 예외가 **unrecognized** 인 경우 ( `HttpException` 또는 `HttpException`에서 상속되는 클래스가 아님) 클라이언트는 다음과 같은 기본 JSON 응답을받습니다.

```javascript
{
  "statusCode": 500,
  "message": "Internal server error"
}
```

## Base exceptions

내장 된 `HttpException`클래스는 `@nestjs/common` 패키지에서 공개됩니다.

`CatsController`에는 `findAll()` 메소드 (`GET` 경로 핸들러)가 있습니다. 어떤 이유로 이 라우트 핸들러에서 예외가 발생한다고 가정해 봅시다. 이를 설명하기 위해 다음과 같이 하드 코딩합니다.

```typescript
@@filename(cats.controller)
@Get()
async findAll() {
  throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
```

> info **힌트** 여기서는 `HttpStatus`를 사용했습니다. 이것은 `@nestjs/common` 패키지에서 가져온 헬퍼 열거형입니다.

클라이언트가 이 엔드 포인트를 호출하면 응답은 다음과 같습니다.

```javascript
{
  "statusCode": 403,
  "message": "Forbidden"
}
```

`HttpException` 생성자는 응답을 결정하는 두 가지 필수 인수를 사용합니다.

* `response` 인수는 JSON 응답 본문을 정의합니다. 아래에 설명 된대로 `문자열` 또는 `객체`일 수 있습니다.
* `status` 인수는 [HTTP 상태 코드](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)를 정의합니다.

기본적으로 JSON 응답 본문에는 두 가지 속성이 있습니다.

* `statusCode`: `status` 인수에 제공된 HTTP 상태 코드로 기본 설정
* `message`: `상태`에 기반한 HTTP 에러에 대한 간단한 설명

JSON 응답 본문의 메시지 부분 만 재정의하려면 `response` 인수에 문자열을 제공하십시오.

전체 JSON 응답 본문을 재정의하려면 `response` 인수에 객체를 전달하십시오. Nest는 객체를 직렬화하여 JSON 응답 본문으로 반환합니다.

두 번째 생성자 인자 `status`는 유효한 HTTP 상태 코드 여야합니다. 모범 사례는`@nestjs/common`에서 가져온 `HttpStatus` 열거 형을 사용하는 것입니다.

다음은 전체 응답 본문을 재정의 하는 예입니다.

```typescript
@@filename(cats.controller)
@Get()
async findAll() {
  throw new HttpException({
    status: HttpStatus.FORBIDDEN,
    error: 'This is a custom message',
  }, 403);
}
```

위의 방법을 사용하면 다음과 같이 응답이 나타납니다.

```javascript
{
  "status": 403,
  "error": "This is a custom message"
}
```

## Exceptions hierarchy

**예외 계층 구조**를 직접 만드는 것이 좋습니다. 이것은 사용자 정의 HTTP 예외가 기본 `HttpException` 클래스에서 상속되어야 함을 의미합니다. 결과적으로 Nest는 예외를 인식하고 자동으로 오류 응답을 처리합니다. 그러한 커스텀 예외를 구현해 봅시다 :

```typescript
@@filename(forbidden.exception)
export class ForbiddenException extends HttpException {
  constructor() {
    super('Forbidden', HttpStatus.FORBIDDEN);
  }
}
```

`ForbiddenException`은 기본 `HttpException`을 확장하므로 내장 예외 핸들러와 완벽하게 작동하므로 `findAll()` 메소드 내에서 사용할 수 있습니다.

```typescript
@@filename(cats.controller)
@Get()
async findAll() {
  throw new ForbiddenException();
}
```

## HTTP exceptions

상용구 코드를 작성할 필요성을 줄이기 위해 Nest는 코어 `HttpException`에서 상속되는 사용 가능한 예외 세트를 제공합니다. 이들 모두는 `@nestjs/common` 패키지에서 공개됩니다:

* `BadRequestException`
* `UnauthorizedException`
* `NotFoundException`
* `ForbiddenException`
* `NotAcceptableException`
* `RequestTimeoutException`
* `ConflictException`
* `GoneException`
* `PayloadTooLargeException`
* `UnsupportedMediaTypeException`
* `UnprocessableEntityException`
* `InternalServerErrorException`
* `NotImplementedException`
* `BadGatewayException`
* `ServiceUnavailableException`
* `GatewayTimeoutException`

## Exception filters

기본 (내장) 예외 필터가 많은 경우를 자동으로 처리 할 수 있지만 예외 레이어를 **완전히 제어** 할 수 있습니다. 예를 들어, 일부 동적 요인에 따라 로깅을 추가하거나 다른 JSON 스키마를 사용할 수 있습니다. **예외 필터**는 이 목적을 위해 설계되었습니다.

`HttpException`클래스의 인스턴스인 예외를 포착하고 이에 대한 사용자 정의 응답 로직을 구현하는 예외 필터를 작성해 봅시다.

```typescript
@@filename(http-exception.filter)
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  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,
      });
  }
}
@@switch
import { Catch, HttpException } from '@nestjs/common';

@Catch(HttpException)
export class HttpExceptionFilter {
  catch(exception, host) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();
    const status = exception.getStatus();

    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
      });
  }
}
```

> info **힌트** 모든 예외 필터는 일반 `ExceptionFilter <T>` 인터페이스를 구현해야 합니다. 이를 위해서는`catch (exception: T, host: ArgumentsHost)`메소드에 표시된 서명을 제공해야 합니다. `T`는 예외 유형을 나타냅니다.

`@Catch (HttpException)` 데코레이터는 필요한 메타 데이터를 예외 필터에 바인딩하여 이 특정 필터가 `HttpException`유형의 예외를 찾고 있음을 Nest에게 알려줍니다. `@Catch()` 데코레이터는 단일 매개 변수 또는 쉼표로 구분된 목록을 사용할 수 있습니다. 이를 통해 여러 유형의 예외에 대한 필터를 한 번에 설정할 수 있습니다.

## Arguments host

`catch()` 메소드의 매개 변수를 보자. `exception` 매개 변수는 현재 처리중인 예외 객체입니다. `host` 매개 변수는 `ArgumentsHost` 객체입니다. `ArgumentsHost`는 **original** 요청 핸들러 (예외가 발생한 곳)에 전달된 인수를 감싸는 래퍼입니다. 여기에는 응용 프로그램 및 사용중인 플랫폼의 유형에 따라 특정 인수 배열이 포함됩니다. 다음은 `ArgumentsHost`의 모습입니다 :

```typescript
export interface ArgumentsHost {
  getArgs<T extends Array<any> = any[]>(): T;
  getArgByIndex<T = any>(index: number): T;
  switchToRpc(): RpcArgumentsHost;
  switchToHttp(): HttpArgumentsHost;
  switchToWs(): WsArgumentsHost;
}
```

`ArgumentsHost`는 다양한 애플리케이션 컨텍스트에서 기본 배열에서 올바른 인수를 선택하는 데 도움이 되는 편리한 메소드 세트를 제공합니다. 다시 말해, `ArgumentsHost`는 **인자 배열**에 지나지 않습니다. 예를 들어, HTTP 애플리케이션 컨텍스트 내에서 필터를 사용하면 `ArgumentsHost`에 `[request, response]`배열이 포함됩니다. 그러나 현재 컨텍스트가 웹 소켓 애플리케이션인 경우 해당 컨텍스트에 적합한 `[client, data]`배열이 포함됩니다. 이 방법을 사용하면 사용자 정의 `catch()`메소드에서 원래 핸들러로 전달되는 인수에 액세스 할 수 있습니다.

## Binding filters

새로운 `HttpExceptionFilter`를 `CatsController`의 `create()`메소드에 묶어 봅시다.

```typescript
@@filename(cats.controller)
@Post()
@UseFilters(new HttpExceptionFilter())
async create(@Body() createCatDto: CreateCatDto) {
  throw new ForbiddenException();
}
@@switch
@Post()
@UseFilters(new HttpExceptionFilter())
@Bind(Body())
async create(createCatDto) {
  throw new ForbiddenException();
}
```

> info **힌트** `@UseFilters()` 데코레이터는 `@nestjs/common` 패키지에서 가져옵니다.

우리는`@UseFilters()`데코레이터를 사용했습니다. `@Catch()`데코레이터와 유사하게 단일 필터 인스턴스 또는 쉼표로 구분된 필터 인스턴스 목록을 사용할 수 있습니다. 여기서는 `HttpExceptionFilter`인스턴스를 작성했습니다. 또는 인스턴스 대신 클래스를 전달하여 프레임 워크에 인스턴스화에 대한 책임을 남기고 **종속 주입**을 활성화 할 수 있습니다.

```typescript
@@filename(cats.controller)
@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
  throw new ForbiddenException();
}
@@switch
@Post()
@UseFilters(HttpExceptionFilter)
@Bind(Body())
async create(createCatDto) {
  throw new ForbiddenException();
}
```

> info **힌트** 가능한 경우 인스턴스 대신 클래스를 사용하여 필터를 적용하는 것이 좋습니다. Nest가 전체 모듈에서 동일한 클래스의 인스턴스를 쉽게 재사용할 수 있으므로 **메모리 사용량**이 줄어 듭니다.

위의 예에서 `HttpExceptionFilter`는 단일 `create()`라우트 핸들러에만 적용되어 메소드 범위가 됩니다. 예외 필터는 메소드 범위, 컨트롤러 범위 또는 전역 범위의 다른 수준으로 범위를 지정할 수 있습니다. 예를 들어, 필터를 컨트롤러 범위로 설정하려면 다음을 수행하십시오.

```typescript
@@filename(cats.controller)
@UseFilters(new HttpExceptionFilter())
export class CatsController {}
```

이 구조는 `CatsController` 안에 정의된 모든 경로 핸들러에 대해 `HttpExceptionFilter`를 설정합니다.

전역 범위 필터를 만들려면 다음을 수행하십시오.

```typescript
@@filename(main)
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new HttpExceptionFilter());
  await app.listen(3000);
}
bootstrap();
```

> warning **경고** `useGlobalFilters ()` 메소드는 게이트웨이 또는 하이브리드 애플리케이션에 대한 필터를 설정하지 않습니다.

전역 범위 필터는 모든 컨트롤러와 모든 경로 처리기에 대해 전체 응용 프로그램에서 사용됩니다. 의존성 주입의 관점에서, 모듈 외부에서 등록 된 전역 필터 (위의 예에서와 같이`useGlobalFilters()`로)는 모듈의 컨텍스트 외부에서 수행되기 때문에 의존성을 주입할 수 없습니다. 이 문제를 해결하기 위해 다음 구성을 사용하여 **모든 모듈에서 직접** 전역 필터를 등록 할 수 있습니다.

```typescript
@@filename(app.module)
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
    },
  ],
})
export class AppModule {}
```

> info **힌트** 이 접근 방식을 사용하여 필터에 대한 의존성 주입을 수행할 때 이 구성이 사용되는 모듈에 관계없이 필터는 실제로 전역적입니다. 어디에서 해야 합니까? 필터 (위 예에서 `HttpExceptionFilter`)가 정의 된 모듈을 선택하십시오. 또한 커스텀 프로 바이더 등록을 다루는 유일한 방법은 `useClass`가 아닙니다. [여기](https://app.gitbook.com/fundamentals/custom-providers)에 대해 자세히 알아보십시오.

이 기술을 사용하여 필요한만큼 필터를 추가 할 수 있습니다. 간단히 공급자 배열에 각각을 추가하십시오.

## Catch everything

처리되지 않은 예외 (예외 유형에 관계없이)를 모두 잡으려면 `@Catch()`데코레이터의 매개 변수 목록을 비워 두십시오 (예: `@Catch()`).

```typescript
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';

@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();

    const status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}
```

위의 예에서 필터는 유형 (클래스)에 관계없이 발생 된 각 예외를 포착합니다.

## Inheritance

일반적으로 응용 프로그램 요구 사항을 충족하도록 제작된 완전히 사용자 지정된 예외 필터를 만듭니다. 그러나 내장된 기본 **전역 예외 필터**를 단순히 확장하고 특정 요인에 따라 동작을 재 정의하려는 경우 사용 사례가 있을 수 있습니다.

예외 처리를 기본 필터에 위임하려면 `BaseExceptionFilter`를 확장하고 상속 된 `catch()`메소드를 호출해야합니다.

```typescript
@@filename(all-exceptions.filter)
import { Catch, ArgumentsHost } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';

@Catch()
export class AllExceptionsFilter extends BaseExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    super.catch(exception, host);
  }
}
@@switch
import { Catch } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';

@Catch()
export class AllExceptionsFilter extends BaseExceptionFilter {
  catch(exception, host) {
    super.catch(exception, host);
  }
}
```

> warning **경고** `BaseExceptionFilter`를 확장하는 메서드 범위 및 컨트롤러 범위 필터는 `new`로 인스턴스화하면 안됩니다. 대신 프레임 워크에서 자동으로 인스턴스화하십시오.

위의 구현은 접근 방식을 보여주는 쉘일뿐입니다. 확장 예외 필터 구현에는 맞춤형 **비즈니스** 논리 (예: 다양한 조건 처리)가 포함됩니다.

전역 필터 는 기본 필터를 확장 **할 수 있습니다**. 이것은 두 가지 방법 중 하나로 수행 할 수 있습니다.

첫 번째 방법은 커스텀 글로벌 필터를 인스턴스화 할 때 `HttpServer` 참조를 삽입하는 것입니다.

```typescript
async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const { httpAdapter } = app.get(HttpAdapterHost);
  app.useGlobalFilters(new AllExceptionsFilter(httpAdapter));

  await app.listen(3000);
}
bootstrap();
```

두 번째 방법은  [여기에 표시된](https://app.gitbook.com/s/-LpOhNvIYtogx8UUAkWn/overview/exception-filters#binding-filters) `APP_FILTER`토큰을 사용하는 것입니다.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jakekwak.gitbook.io/nestjs/overview/untitled.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
