Skip to content
2 changes: 1 addition & 1 deletion packages/apollo-datasource/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ export interface DataSourceConfig<TContext> {
}

export abstract class DataSource<TContext = any> {
initialize?(config: DataSourceConfig<TContext>): void;
initialize?(config: DataSourceConfig<TContext>): void | Promise<void>;
}
96 changes: 96 additions & 0 deletions packages/apollo-server-core/src/__tests__/dataSources.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { ApolloServerBase } from '../ApolloServer';
import gql from 'graphql-tag';

const typeDefs = gql`
type Query {
hello: String
}
`;

const resolvers = {
Query: {
hello() {
return 'world';
}
},
};

describe('ApolloServerBase dataSources', () => {
it('initializes synchronous datasources from a datasource creator function', async () => {
const initialize = jest.fn();

const server = new ApolloServerBase({
typeDefs,
resolvers,
dataSources: () => ({ x: { initialize }, y: { initialize } })
});

await server.executeOperation({ query: "query { hello }"});

expect(initialize).toHaveBeenCalledTimes(2);
});

it('initializes asynchronous datasources before calling resolvers', async () => {
const expectedMessage = 'success';
let maybeInitialized = 'failure';

const additionalInitializer = jest.fn();

const server = new ApolloServerBase({
typeDefs,
resolvers: {
Query: {
hello(_, __, context) {
return context.dataSources.x.getData();
}
},
},
dataSources: () => ({
x: {
initialize() {
return new Promise(res => { setTimeout(() => {
maybeInitialized = expectedMessage;
res();
}, 200) })
},
getData() { return maybeInitialized; }
},
y: {
initialize() {
return new Promise(res => { setTimeout(() => {
additionalInitializer();
res();
}, 400) })
}
}
})
});

Comment thread
lostfictions marked this conversation as resolved.
const res = await server.executeOperation({ query: "query { hello }"});

expect(res.data?.hello).toBe(expectedMessage);
expect(additionalInitializer).toHaveBeenCalled();
});

it('make datasources available on resolver contexts', async () => {
const message = 'hi from dataSource';
const getData = jest.fn(() => message);

const server = new ApolloServerBase({
typeDefs,
resolvers: {
Query: {
hello(_, __, context) {
return context.dataSources.x.getData();
}
},
},
dataSources: () => ({ x: { initialize() {}, getData } })
});

const res = await server.executeOperation({ query: "query { hello }"});

expect(getData).toHaveBeenCalled();
expect(res.data?.hello).toBe(message);
});
});
6 changes: 3 additions & 3 deletions packages/apollo-server-core/src/requestPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export async function processGraphQLRequest<TContext>(

const dispatcher = initializeRequestListenerDispatcher();

initializeDataSources();
await initializeDataSources();

const metrics = requestContext.metrics || Object.create(null);
if (!requestContext.metrics) {
Expand Down Expand Up @@ -611,15 +611,15 @@ export async function processGraphQLRequest<TContext>(
return new GraphQLExtensionStack(extensions);
}

function initializeDataSources() {
async function initializeDataSources() {
if (config.dataSources) {
const context = requestContext.context;

const dataSources = config.dataSources();

for (const dataSource of Object.values(dataSources)) {
if (dataSource.initialize) {
dataSource.initialize({
await dataSource.initialize({
context,
cache: requestContext.cache,
});
Expand Down