Following the Apollo Server docs on dataSources, one would assume that the best way to access data in a GraphQL resolver would be through the dataSources
option on the server config.
However, the app I'm working on has requirements that result in many different data source classes (truncated into ...
in my handler.ts file below, but there are about 10 now and there will be many more in the future). This means that every data source class will be instantiated for each query/mutation the server receives, which I'm thinking could eventually result in a bit of latency if I have enough data source classes.
I'm thinking of not using the dataSources
option and instead just instantiating each data source class as necessary by using the resolver context to call the initialize()
method on the Apollo RESTDataSource
class (sample resolver method pasted below), which seems to provide all the same functionality to the data source class that the dataSources
config option does.
I'm wondering:
- Are there any benefits / disadvantages of using the
dataSources
option that I'm not aware of? - Why would the Apollo docs encourage you to instantiate all data source classes for each request?
Thanks in advance for any insight you may have!
Server config from handler.ts:
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
playground: true,
dataSources: (): IDataSources => {
return {
entity: new Entity(),
notes: new Notes(), // this could be removed if "new" resolver method is used
... // like 8 more data sources go here
};
},
context: ({
event,
context
}: {
event: APIGatewayEvent;
context: Context;
}): IGraphqlServerOptionContext => {
const user = new User(event);
return { apiGatewayEvent: event, apiGatewayContext: context, user };
},
extensions: [() => new LogFunctionExtension()]
});
Sample (alternative) resolver method from resolvers.ts:
export const resolvers: IResolvers<any, IResolverContext> = {
Query: {
getNotes: async (
_source,
args: QueryGetNotesArgs,
resolverContext: IResolverContext
) => {
validateRequestHeaders('common', resolverContext.apiGatewayEvent);
// old method of accessing notes data source class:
// const {
// dataSources: { notes }
// } = resolverContext;
// new method of accessing notes data source class:
const notes = new Notes(resolverContext);
return notes.getNoteDetails(args);
},
}
};
new Notes data source class constructor:
export default class Notes extends RESTDataSource<IDataSourceContext> {
constructor(inputContext: IDataSourceContext) {
this.initialize({
context: inputContext,
cache: new InMemoryLRUCache()
});
}
}