NestJS GraphQL 数据源

Posted

技术标签:

【中文标题】NestJS GraphQL 数据源【英文标题】:NestJS GraphQL DataSources 【发布时间】:2019-06-28 07:05:55 【问题描述】:

警告以下代码不正确,需要根据请求创建数据源。

请勿使用以下代码

我正在尝试将 apollo-rest-datasource 与 NestJS 一起使用。我看到的缺点是数据源不参与 NestJS 的 DI 系统。

我可以通过让 NestJS 实例化单例数据源,然后使用 GraphQLModule.forRootAsync 将这些实例注入 Apollo 服务器的 dataSources 属性来解决此问题。

 GraphQLModule.forRootAsync(
      imports: [
        DataSourcesModule
      ],
      useFactory: (...args: DataSource[]) => 
        return 
          typePaths: ['./**/*.graphql'],
          context: (req: req: Request) => ( token: req.headers.authorization ),
          playground: true,
          dataSources: () => 
            let dataInstances =  as any;
            args.forEach(arg => 
              const dataSource = arg as any;
              dataInstances[dataSource.constructor.name] = arg;
            );
            return dataInstances;
          ,
        ;
      ,
      inject: [...dataSources]

我现在让 DI 在我的 DataSource 中工作,并且可以在解析器中使用 DI 来包含我的 DataSource 实例(而不是从 GraphQL 上下文访问)。虽然这有效,但感觉不对。

对于 NestJS 的 DI 和 Apollo GraphQL 上下文是否有更好的方法?

【问题讨论】:

您好,我目前正在研究将 Nest 与 GraphQL 结合使用,请问您为什么决定使用 apollo rest 数据源而不是常规的 nest http 客户端?感谢您的帮助! Apollo 数据源提供了一种缓存机制来防止重复的 http 响应。 【参考方案1】:

我能够通过在我的每个解析器方法上使用 @Context 装饰器来解决这个问题,以便获取数据源。以here 为例的完整答案。

【讨论】:

【参考方案2】:

RESTDataSource 看起来只是一个普通的类。您应该能够简单地应用 @Injectable() 装饰器并将它们视为常规的 Nest 服务。这将允许您将依赖项注入到它们中,并将数据源注入到您的解析器中,而无需像您展示的那样在 GraphQLModule 中引导事物。

const  RESTDataSource  = require('apollo-datasource-rest');
import  Injectable  from '@nestjs/common';

@Injectable()
class MoviesAPI extends RESTDataSource 
  // Inject whatever Nest dependencies you want
  constructor(private readonly someDependency: SomeDependency) 
    super();
    this.baseURL = 'https://movies-api.example.com/';
  

  async getMovie(id) 
    return this.get(`movies/$id`);
  

  async getMostViewedMovies(limit = 10) 
    const data = await this.get('movies', 
      per_page: limit,
      order_by: 'most_viewed',
    );
    return data.results;
  


@Injectable()
class ResolverClass 
   // Inject your datasources
   constructor(private readonly moviesApi: MoviesAPI)  

您只需确保将您的 DataSource 类放入适当的 Nest 模块的提供者中,如果还需要从其他模块中使用它们,则可以选择导出它们。

更新: 由于数据源也需要传递给 ApolloServer,因此您可以通过引入自己的装饰器来应用到每个数据源,然后使用反射来“发现”应用程序中存在的所有源,从而可能以更嵌套的方式执行此操作。这不是目前记录良好的内容,但您可以查看一些 Nest 源代码中的示例,了解如何完成此操作。 For reference here's the code that discovers all of the @Resolver decorated classes for the GraphQL module.

它基本上归结为使用ModulesContainerMetadataScanner 来查找应用程序中存在的所有提供程序,然后过滤以查找哪些提供程序应用了您的自定义装饰器。 (例如@DataSource())。

我认为你现在拥有的不一定是一个大问题,但如果你以这种方式实现它,你就不必担心每次都要记住添加新的数据源。

【讨论】:

是的,这就是我正在做的事情,但是 Apollo Server 需要将 DataSources 定义为 datasources 的属性,以便使用其他 Apollo Server 功能对其进行属性实例化。 我想我得到的是你上面的作品。这就是我目前正在做的事情。把这两个概念混在一起感觉很奇怪。我想没关系?! @cgatian 我已经更新了答案,为您提供一些提示,告诉您如何以更类似于 NestJS 的方式实现此功能,从而自动发现您的数据源 好建议,我不知道存在。 如果您不使用 DataSource 类中的方法 willSendRequest (例如,将令牌添加到请求标头中),它将起作用。我可以实现的唯一方法是将数据源字典传递到GraphQLModule

以上是关于NestJS GraphQL 数据源的主要内容,如果未能解决你的问题,请参考以下文章

GraphQL介绍&使用nestjs构建GraphQL查询服务

nestjs graphql - 保留数据并将其用于其他请求

使用 NestJS、TypeORM、GraphQL 更新具有实体之间关系的 PSQL 表

Nestjs(graphql)中不同类型的异常处理

nestjs : 定义要在 mongoose 和 graphql 中使用的地图/数组

如何使用 GRAPHQL 测试 e2e Nestjs API