警告以下代码是需要根据请求创建的错误数据源。
请勿使用下面的代码
我正在尝试对NestJS使用apollo-rest-datasource
。我看到的缺点是数据源不参与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]
我现在可以在我的DataSource中使用DI,并且可以在解析器中使用DI来包含我的DataSource实例(而不是从GraphQL上下文进行访问)。虽然这样做有效,但感觉很不对劲。
NestJS的DI和Apollo GraphQL上下文是否有更好的方法?
答案 0 :(得分:1)
RESTDataSource看起来只是一个普通的类。您应该能够简单地应用@Injectable()
装饰器并将其视为常规的Nest服务。这样一来,您就可以将依赖项注入到它们之中,也可以将DataSources注入到您的解析器中,而不必像已经显示的那样在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。
它基本上可以归结为使用ModulesContainer
和MetadataScanner
查找应用程序中存在的所有提供程序,然后进行过滤以查找哪些应用了您的自定义装饰器的提供程序。 (例如@DataSource()
)。
我认为您现在所拥有的并不一定是一个大问题,但是如果您以这种方式实现它,则不必担心每次都记得添加新的dataSources。
答案 1 :(得分:-1)
我能够通过在每个解析器方法上使用@Context
装饰器来解决此问题,以获取数据源。带有示例here的完整答案。