# Caching

## Caching

캐싱은 앱의 성능을 향상시키는 데 도움이되는 훌륭하고 간단한 **기술**입니다. 고성능 데이터 액세스를 제공하는 임시 데이터 저장소 역할을합니다.

## Installation

먼저 필요한 패키지를 설치하십시오.

```bash
$ npm install --save cache-manager
```

## In-memory cache

Nest는 다양한 캐시 스토리지 제공자를 위한 통합 API를 제공합니다. 내장된 것은 인 메모리 데이터 저장소입니다. 그러나 Redis와 같은 보다 포괄적인 솔루션으로 쉽게 전환할 수 있습니다. 캐싱을 활성화하려면 먼저 `CacheModule`을 가져 와서 `register()` 메소드를 호출하십시오.

```typescript
import { CacheModule, Module } from '@nestjs/common';
import { AppController } from './app.controller';

@Module({
  imports: [CacheModule.register()],
  controllers: [AppController],
})
export class ApplicationModule {}
```

그런 다음 데이터를 캐시할 위치에 `CacheInterceptor`를 연결하십시오.

```typescript
@Controller()
@UseInterceptors(CacheInterceptor)
export class AppController {
  @Get()
  findAll(): string[] {
    return [];
  }
}
```

> warning **경고** `GET` 엔드 포인트만 캐시됩니다. 또한 원시 응답 오브젝트 (`@Res()`)를 주입하는 HTTP 서버 라우트는 캐시 인터셉터를 사용할 수 없습니다. 자세한 내용은  [응답 매핑](https://docs.nestjs.com/interceptors#response-mapping)을 참조하십시오.

## Global cache

필요한 상용구의 양을 줄이려면 `CacheInterceptor`를 전역으로 모든 엔드 포인트에 바인딩 할 수 있습니다.

```typescript
import { CacheModule, Module, CacheInterceptor } from '@nestjs/common';
import { AppController } from './app.controller';
import { APP_INTERCEPTOR } from '@nestjs/core';

@Module({
  imports: [CacheModule.register()],
  controllers: [AppController],
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: CacheInterceptor,
    },
  ],
})
export class ApplicationModule {}
```

## WebSockets & Microservices

MicroService의 패턴뿐만 아니라 WebSocket 가입자에게 `CacheInterceptor`를 적용할 수도 있습니다 (사용중인 전송 방법에 관계없이).

```typescript
@@filename()
@CacheKey('events')
@UseInterceptors(CacheInterceptor)
@SubscribeMessage('events')
handleEvent(client: Client, data: string[]): Observable<string[]> {
  return [];
}
@@switch
@CacheKey('events')
@UseInterceptors(CacheInterceptor)
@SubscribeMessage('events')
handleEvent(client, data) {
  return [];
}
```

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

그러나 캐시된 데이터를 저장하고 검색하는 데 사용되는 키를 지정하려면 추가`@CacheKey()`데코레이터가 필요합니다. 또한 **모든 것을 캐시하지 않아야합니다**. 단순히 데이터를 쿼리하지 않고 일부 비즈니스 작업을 수행하는 작업은 캐시되지 않아야 합니다.

## Customize caching

캐시된 모든 데이터에는 자체 TTL (만료 시간)이 있습니다. 기본값을 사용자 정의하려면 options 객체를 `register()`메서드에 전달하십시오.

```typescript
CacheModule.register({
  ttl: 5, // seconds
  max: 10, // maximum number of items in cache
});
```

## Different stores

이 서비스는 후드에서 [cache-manager](https://github.com/BryanDonovan/node-cache-manager)를 활용합니다. `cache-manager` 패키지는 [Redis](https://github.com/dabroek/node-cache-manager-redis-store)와 같은 다양한 유용한 저장소를 지원합니다. 지원되는 전체 저장소 목록은 [여기](https://github.com/BryanDonovan/node-cache-manager#store-engines)에서 확인할 수 있습니다. Redis 스토어를 설정하려면 해당 옵션과 함께 패키지를 `register()`메소드에 전달하면 됩니다.

```typescript
import * as redisStore from 'cache-manager-redis-store';
import { CacheModule, Module } from '@nestjs/common';
import { AppController } from './app.controller';

@Module({
  imports: [
    CacheModule.register({
      store: redisStore,
      host: 'localhost',
      port: 6379,
    }),
  ],
  controllers: [AppController],
})
export class ApplicationModule {}
```

## Adjust tracking

기본적으로 Nest는 요청 URL (HTTP 앱) 또는 캐시 키 (웹 소켓 및 마이크로 서비스 앱, `@CacheKey()`데코레이터를 통해 설정)를 사용하여 캐시 레코드를 엔드 포인트와 연결합니다. 그럼에도 불구하고 때로는 HTTP 헤더 (예: `profile` 엔드 포인트를 올바르게 식별하기위한 `Authorization`)를 사용하는 등 다양한 요소를 기반으로 추적을 설정하고자 할 수 있습니다.

이를 위해 `CacheInterceptor`의 서브 클래스를 작성하고 `trackBy()`메소드를 대체하십시오.

```typescript
@Injectable()
class HttpCacheInterceptor extends CacheInterceptor {
  trackBy(context: ExecutionContext): string | undefined {
    return 'key';
  }
}
```

## Async configuration

컴파일시 정적으로 전달하는 대신 모듈 옵션을 비동기적으로 전달할 수 있습니다. 이 경우 비동기 구성을 처리하는 몇 가지 방법을 제공하는 `registerAsync()` 메소드를 사용하십시오.

한 가지 방법은 팩토리 기능을 사용하는 것입니다.

```typescript
CacheModule.registerAsync({
  useFactory: () => ({
    ttl: 5,
  }),
});
```

Our factory behaves like all other asynchronous module factories (it can be `async` and is able to inject dependencies through `inject`).

```typescript
CacheModule.registerAsync({
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    ttl: configService.getString('CACHE_TTL'),
  }),
  inject: [ConfigService],
});
```

Alternatively, you can use the `useClass` method:

```typescript
CacheModule.registerAsync({
  useClass: CacheConfigService,
});
```

위의 구성은 `CacheModule`내에서 `CacheConfigService`를 인스턴스화하여 옵션 객체를 얻는 데 사용합니다. `CacheConfigService`는 설정 옵션을 제공하기 위해 `CacheOptionsFactory` 인터페이스를 구현해야 합니다:

```typescript
@Injectable()
class CacheConfigService implements CacheOptionsFactory {
  createCacheOptions(): CacheModuleOptions {
    return {
      ttl: 5,
    };
  }
}
```

다른 모듈에서 가져온 기존 구성 공급자를 사용하려면 `useExisting` 구문을 사용하십시오.

```typescript
CacheModule.registerAsync({
  imports: [ConfigModule],
  useExisting: ConfigService,
});
```

이것은 `useClass`와 동일하게 작동하며 한 가지 중요한 차이점이 있습니다. `CacheModule`은 가져온 모듈을 찾아서 자체적으로 인스턴스화 하는 대신 이미 작성된 `ConfigService`를 재사용합니다.
