Я хочу реализовать пользовательское кэширование в Nestjs - PullRequest
0 голосов
/ 04 февраля 2019

Механизм кэширования по умолчанию в nsetjs не дает достаточной гибкости, поскольку вы не можете аннотировать отдельные маршруты / методы с помощью директивы @Cache или чего-то в этом роде.

Я хочу бытьвозможность настраивать ttl, а также я не хочу кэшировать каждый маршрут. Может быть, для этого даже имеет смысл переместить кэширование на уровень обслуживания, пока не уверен.

Просто интересно, как бы высделать это лучше с помощью фреймворка nestjs.Просто для кеширования конкретных маршрутов или методов обслуживания.

1 Ответ

0 голосов
/ 04 февраля 2019

Я недавно начал работать над модулем кэширования для NestJS после того, как столкнулся с теми же проблемами, что и вы.Он доступен на npm в @nestjs-plus/caching, хотя он еще не готов к использованию, но я поделюсь здесь определением Interceptor.Он полагается на шаблон mixin, чтобы иметь возможность получать данные по маршруту.

import { makeInjectableMixin } from '@nestjs-plus/common';
import {
  ExecutionContext,
  Inject,
  Injectable,
  NestInterceptor
} from '@nestjs/common';
import { forkJoin, Observable, of } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';
import { Cache, CacheToken } from './cache';

@Injectable()
export abstract class CachingInterceptor implements NestInterceptor {
  protected abstract readonly options: CacheOptions;

  constructor(@Inject(CacheToken) private readonly cache: Cache) {}

  async intercept(
    context: ExecutionContext,
    call$: Observable<any>
  ): Promise<Observable<any>> {
    const http = context.switchToHttp();
    const request = http.getRequest();
    const key = this.options.getKey(request);

    const cached = await this.cache.get(key);
    if (cached != null) {
      return of(cached);
    }

    return call$.pipe(
      switchMap(result => {
        return forkJoin(
          of(result),
          this.cache.set(key, result, this.options.ttl)
        ).pipe(catchError(e => of(result)));
      }),
      map(([result, setOp]) => result)
    );
  }
}

export interface CacheOptions {
  ttl: number;
  getKey: (request) => string;
}

export const makeCacheInterceptor = (options: CacheOptions) => {
  return makeInjectableMixin('CachingInterceptor')(
    class extends CachingInterceptor {
      protected readonly options = options;
    }
  );
};

export interface Cache {
  get: (key: string) => Promise<any | null | undefined>;
  set: (key: string, data: any, ttl: number) => Promise<void>;
  del: (key: string) => Promise<void>;
}

export const CacheToken = Symbol('CacheToken');

Этот шаблон позволяет применять кэширование для маршрута в ваших контроллерах с различными TTL или методами извлечения ключа кэша из входящего запроса..

@Get()
  @UseInterceptors(
    makeCacheInterceptor({
      getKey: () => '42' // could be req url, query params, etc,
      ttl: 5,
    }),
  )
  getHello(): string {
    return this.appService.getHello();
  }

Единственное, чего здесь не хватает (и библиотеки, над которой я работаю), является гибкий набор реализаций кеша, таких как память, redis, db и т. Д. Я планирую интегрировать с кешем.-manager библиотека, чтобы заполнить этот пробел на этой неделе (это тот же поставщик кеша, который Nest использует для реализации Cache по умолчанию).Не стесняйтесь использовать это в качестве основы для создания своего собственного или следите за обновлениями, когда @nestjs-plus/caching готов к использованию.Я обновлю этот вопрос позже на этой неделе, когда опубликую готовую производственную версию.

...