NestJS GraphQL 数据源

NestJS GraphQL DataSources

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

请勿使用以下代码

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

我可以通过让 NestJS 实例化单例数据源然后使用 GraphQLModule.forRootAsync 将这些实例注入 Apollo Server 的 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 上下文是否有更好的方法?

RESTDataSource 看起来只是一个普通的 class。您应该能够简单地应用 @Injectable() 装饰器并将它们视为常规 Nest 服务。这将允许您将依赖项注入到它们中,并将数据源注入到您的解析器中,而不需要 bootstrap 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 classes 放入适当的 Nest 模块的提供程序中,如果它们也需要从其他模块使用,则可以选择导出它们。

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

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

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

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