LoopBack4:拦截器内部的访问存储库

时间:2019-09-30 09:36:15

标签: typescript express loopbackjs v4l2loopback loopback4

我想在我的LoopBack4应用程序中增强一个Interceptor,该应用程序目前仅在命令行上向我显示控制器方法调用的开始和结束-如此处所述:https://loopback.io/doc/en/lb4/Interceptors.html

我的日志拦截器看起来像这样:

export const Log: Interceptor = async (invocationCtx, next) => {
    // Wait until the interceptor/method chain returns
    const req = await invocationCtx.get(RestBindings.Http.REQUEST);

    try
    {
        const stackinfo = 'Class: ' + invocationCtx.targetClass.name + ' | Method: ' + invocationCtx.methodName + " | Request IPs: " + req.ips.concat(', ');

        logger.trace('Starting - ' + stackinfo);

        const result = await next();
        const res = await invocationCtx.get(RestBindings.Http.RESPONSE);

        logger.trace('Ending - ' + stackinfo + ' | Response Status Code: ' + res.statusCode);

        return result;
    }
    catch (e)
    {
        logger.error(e);
        throw e;
    }
};

现在,我想增强此拦截器的功能,以便将一些统计数据也记录到我的MySQL-Datasource中。我的问题是,如何访问拦截器中的存储库?我是否必须注入存储库?如果是,我该怎么做?还是有更好的方法来实现这一目标?

2 个答案:

答案 0 :(得分:0)

我自己找到了一个解决方案:

  1. 创建服务:
export class StatisticService
{
    constructor(
        @repository(StatisticRecordRepository) public statisticsRepository: StatisticRecordRepository
    ) {}


    async increment(key: string, addend = 1): Promise<void>
    {
        const existing = await this.statisticsRepository.findOne({where: {StatsKey: key}});
        if(existing !== null)
        {
            // @ts-ignore
            existing.Counter = existing.Counter + addend;
            existing.UpdateTs = (new Date()).toISOString();
            await this.statisticsRepository.update(existing);
        }
        else
        {
            await this.statisticsRepository.create(new StatisticRecord({
                                                                           StatsKey: key,
                                                                           Counter:  addend
                                                                       }));
        }
    }
}


export const StatisticsServiceBindings = {
    VALUE: BindingKey.create<StatisticService>("services.StatisticsService")
};
  1. 将服务绑定到Application构造函数中:
this.bind(StatisticsServiceBindings.VALUE).toClass(StatisticService);
  1. 在日志拦截器中获取并使用服务:
const stats = await invocationCtx.get(StatisticsServiceBindings.VALUE);
stats.increment(invocationCtx.targetClass.name + '::' + invocationCtx.methodName + ' [' + res.statusCode + ']');

答案 1 :(得分:0)

您可以像这样通过invocationCtx.target访问拦截器中的存储库:

export const exampleInterceptor: Interceptor = async (invocationCtx, next) => {
  const exampleRepo = invocationCtx.target.exampleRepository;
  const anotherExampleRepo = invocationCtx.target.anotherExampleRepository;
};

假设您的拦截器将在控制器中有相应的@repository装饰器(可同时使用类级别和方法级别的拦截器)

@intercept(exampleInterceptor)
export class ExampleController {
  constructor(
    @repository(ExampleRepository)
    public exampleRepository: ExampleRepository,
    @repository(AnotherExampleRepository)
    public anotherExampleRepository: AnotherExampleRepository
  ) {}
}

不确定这是否是推荐的解决方案。很想听听其他建议。

相关问题