【问题标题】:NestJS GraphQL DataSourcesNestJS GraphQL 数据源
【发布时间】: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 响应。

标签: typescript graphql apollo-server nestjs


【解决方案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
    猜你喜欢
    • 2020-11-04
    • 2021-04-10
    • 2020-05-29
    • 2019-05-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-23
    • 2022-08-11
    • 2021-11-09
    相关资源
    最近更新 更多