【问题标题】:Nestjs - What is the right approach to have custom classes using 3rd party libraries availableNestjs - 使用 3rd 方库提供自定义类的正确方法是什么
【发布时间】:2021-11-24 06:49:14
【问题描述】:

我是 NestJS 的新手,我没有找到任何明确的指示来做我需要做的事情。

我想使用我以前从未使用过但只听说过好东西的 NestJS 来构建我的后端。所以我要构建的后端服务器将使用来自 npmjs 的名为 ccxt 的第 3 方模块。在一个普通的节点应用程序中,我只会创建一个随机类,例如 CryptoManager,导入 ccxt 模块并编写一些按设定间隔或其他方式运行的函数。然后我会创建一个控制器类来实例化 CryptoManager 类的一个对象,然后我可以从那里返回它的响应。

但是我应该如何使用 NestJS 做到这一点?为了让自定义类运行其他嵌套控制器/服务等中可用的后台任务,我需要做什么?

这个类只是应该执行第 3 方 (ccxt) 模块函数并将结果存储在数据库中。但我希望能够从 nestjs 应用程序中的所有点(从所有模块)执行这些类方法。

我希望我的问题很清楚,如果没有,请告诉我。

【问题讨论】:

    标签: node.js nestjs


    【解决方案1】:

    您需要结合使用 ModulesProviders 以“嵌套方式”执行此操作,然后您可以在整个应用中使用依赖注入。

    一般来说,您添加 3rd 方库的方式如下:

    1. 创建一个模块来包装您的库,例如“CryptoManagerModule”。
    2. 创建一个提供 CCXT 库的自定义提供程序,并将其添加到您的 providers 数组中。
    3. 创建服务“CryptoManagerService”,并将 CCXT 注入构造函数。
    4. 从您的模块中导出“CryptoManagerService”,以便您可以将其注入应用的其余部分。
    5. (可选)将您的模块标记为“全局”,这样您只需在 AppModule 中配置该模块一次,即可使其可用于所有其他模块。

    内部crypto-manager.module.ts

    import { DynamicModule, Module, Provider } from '@nestjs/common';
    import { CryptoManagerService } from './crypto-manager.service';
    import * as ccxt from 'ccxt';
    
    // Add any config options you need, like API keys, etc
    export interface CryptoManagerModuleOptions {
      global?: boolean;
    }
    
    export const KRAKEN_CLIENT_TOKEN = 'KRAKEN_CLIENT_TOKEN';
    
    export class CryptoManagerModule {
      static forRoot(options: CryptoManagerModuleOptions): DynamicModule {
        // An example of injecting a single class of ccxt.  Note this is only available
        // within this module.
        const krakenProvider: Provider = {
          provide: KRAKEN_CLIENT_TOKEN,
          useValue: new ccxt.kraken(),
        };
    
        return {
          module: CryptoManagerModule,
          providers: [krakenProvider, CryptoManagerService],
          // Exports can be @Inject()'ed to other files, and if global
          // is set, then forRoot only needs to be called in the AppModule
          exports: [CryptoManagerService],
          global: options.global,
        };
      }
    }
    
    

    内部crypto-manager.service.ts

    import { Inject, Injectable } from '@nestjs/common';
    import { KRAKEN_CLIENT_TOKEN } from './crypto-manager.module';
    import { kraken } from 'ccxt';
    
    @Injectable()
    export class CryptoManagerService {
      constructor(@Inject(KRAKEN_CLIENT_TOKEN) private kraken: kraken) {}
    
      loadKrakenMarkets() {
        return this.kraken.loadMarkets();
      }
    }
    

    内部app.module.ts

    import { Module } from '@nestjs/common';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    import { CryptoManagerModule } from './crypto-manager/crypto-manager.module';
    
    @Module({
      controllers: [AppController],
      providers: [AppService],
      // Make sure to call forRoot
      imports: [CryptoManagerModule.forRoot({ global: true })],
    })
    export class AppModule {}
    
    

    最后,在app.service.ts 中使用它的一个例子。我没有对这个文件做任何特别的事情,你只会看到记录到控制台的结果。

    import { Inject, Injectable } from '@nestjs/common';
    import { CryptoManagerService } from './crypto-manager/crypto-manager.service';
    
    @Injectable()
    export class AppService {
      constructor(private cryptoManagerService: CryptoManagerService) {}
    
      getHello(): string {
        this.cryptoManagerService.loadKrakenMarkets().then(console.log);
        return 'Hello World!';
      }
    }
    

    这样做可以让您在测试时轻松地模拟出kraken,允许您在 forRoot 中传递配置变量以防您想跨项目重用它,并且这种模式在已经是 Nest 社区了。

    【讨论】:

    • 哇,非常感谢您的详细解释,即使使用库本身也是如此。我想知道我是否也可以只声明一个带有 @Injectable 装饰器的类,并且该类实例化了一堆 ccxt.exchange 对象?如果我希望一个经理持有多个交换实例(binance、kraken 等),这也是一种可能的方法吗?类 ExchangeManager(@Injectable 注释)持有 ccxt 交换类型的类变量。
    • 在上例中的“CryptoManagerModule”中,您只需将额外的“提供者”添加到providers 数组中,并将@Inject(EXCHANGE_TOKEN_HERE) 它们添加到服务中,方式与已经存在的相同完成。
    • 是的,这就是我已经做过的,它的工作非常感谢。但我的意思是,如果可能的话,有什么区别,只需创建一个像 @injectable Manager 这样的类,它的私有字段为 exchange1 = new ccxt.exchangeX exchange2 = ccxt.ExchangeY
    • 主要的好处是你有依赖注入,所以在测试中模拟你的交换变得更加简单,因为 Nests 内置在测试工具中。查看有关如何覆盖提供程序的示例:docs.nestjs.com/fundamentals/testing#end-to-end-testing。请记住,您使用的是自定义提供程序,因此您将传递类似.overrideProvider(KRAKEN_CLIENT_TOKEN) 的内容。让我知道这是否有意义!
    • 你就是男人。非常感谢
    【解决方案2】:

    我为此创建了nestjs-ccxt NestJS CCXT 模块包装器https://www.npmjs.com/package/nestjs-ccxt

    首先将CcxtModule 导入为任何其他模块

    import { CcxtModule } from 'nestjs-ccxt';
    
    @Module({
      imports: [CcxtModule.forRoot({ ... })],
    })
    export class AppModule {}
    

    接下来在您的服务中使用普通构造函数注入 CcxtService

    @Injectable()
    export class ExchangeService {
      constructor(private ccxtService: CcxtService) {}
    
      async getBtcUsdtTicker() {
        const client = await this.ccxtService.getClient('binance');
        const ticker = await client.fetchTicker('BTC/USDT');
        return ticker;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-04-11
      • 2019-05-28
      • 1970-01-01
      • 2013-01-17
      • 1970-01-01
      • 2020-08-09
      • 2020-01-04
      • 1970-01-01
      • 2014-12-14
      相关资源
      最近更新 更多