NestJSMiddleTechnical

Как реализовать кэширование в NestJS?

NestJS предоставляет CacheModule из @nestjs/cache-manager. Подключите его глобально, используйте декоратор @CacheKey/@CacheTTL на контроллерах или вызывайте CACHE_MANAGER напрямую через inject.

Кэширование в NestJS

NestJS интегрируется с библиотекой cache-manager через пакет @nestjs/cache-manager. Поддерживаются in-memory хранилище (по умолчанию) и Redis через @keyv/redis или cache-manager-redis-store.

Установка и регистрация

// app.module.ts
import { CacheModule } from '@nestjs/cache-manager';
import { redisStore } from 'cache-manager-redis-store';

@Module({
  imports: [
    CacheModule.registerAsync({
      isGlobal: true,
      useFactory: async () => ({
        store: await redisStore({
          socket: { host: 'localhost', port: 6379 },
        }),
        ttl: 60, // секунд
      }),
    }),
  ],
})
export class AppModule {}

Авто-кэш через CacheInterceptor

Декоратор @UseInterceptors(CacheInterceptor) или глобальная регистрация автоматически кэшируют ответы GET-маршрутов.

import { CacheInterceptor, CacheKey, CacheTTL } from '@nestjs/cache-manager';

@Controller('products')
@UseInterceptors(CacheInterceptor)
export class ProductsController {
  @Get()
  @CacheKey('all-products')
  @CacheTTL(120)
  findAll() {
    return this.productsService.findAll();
  }
}

Ручное управление кэшем

import { Inject } from '@nestjs/common';
import { Cache, CACHE_MANAGER } from '@nestjs/cache-manager';

@Injectable()
export class ProductsService {
  constructor(@Inject(CACHE_MANAGER) private cache: Cache) {}

  async getProduct(id: string) {
    const key = `product:${id}`;
    const cached = await this.cache.get<Product>(key);
    if (cached) return cached;

    const product = await this.repo.findById(id);
    await this.cache.set(key, product, 300);
    return product;
  }

  async invalidate(id: string) {
    await this.cache.del(`product:${id}`);
  }
}

Глобальная регистрация интерсептора

// app.module.ts providers
{
  provide: APP_INTERCEPTOR,
  useClass: CacheInterceptor,
}

Подводные камни

  • CacheInterceptor кэширует только GET-запросы; POST/PUT игнорируются — не стоит ожидать кэша для мутаций.
  • Ключ по умолчанию = URL + query string; у разных пользователей с одинаковым URL кэш будет общим — добавляйте userId в ключ вручную.
  • isGlobal: true важно указывать, иначе каждый модуль создаёт свой изолированный кэш-экземпляр.
  • При обновлении @nestjs/cache-manager v2 токен инъекции изменился с CACHE_MANAGER из @nestjs/common на импорт из @nestjs/cache-manager — путаница ломает DI.
  • TTL задаётся в секундах в cache-manager v5, но в миллисекундах в старых версиях — всегда проверяйте документацию используемой версии.
  • Redis-соединение не восстанавливается автоматически при обрыве — настройте reconnectOnError и мониторинг.
  • Хранение объектов с методами (классов) в кэше теряет прототип после сериализации/десериализации — используйте plain objects или применяйте трансформацию при получении.
  • CacheInterceptor не работает с WebSocket и gRPC транспортами — только HTTP.

Common mistakes

  • Дает общий ответ про Node.js и не называет конкретные API NestJS.
  • Не объясняет, где в lifecycle находится кэширование в NestJS.
  • Не разделяет validation, authorization, business logic и persistence.
  • Игнорирует ошибки, лимиты входных данных, observability и тестирование.

What the interviewer is testing

  • Может объяснить кэширование в NestJS на примере кода.
  • Называет ключевые API: CacheModule, CacheInterceptor.
  • Использует точные API NestJS, а не вымышленные hooks/decorators/methods.
  • Видит production-риски: безопасность, отказоустойчивость, логирование и тесты.

Sources

Related topics

Как реализовать кэширование в NestJS? | Talanto