Apollo-server: Creating DataSources generically

Created on 11 Feb 2019  路  3Comments  路  Source: apollographql/apollo-server

馃憢Hey Apollo team!

We've been excited to start using apollo-server and appreciate all of the hard work you folks are putting into making it great.

We've been looking into creating some data sources for our server and have been challenged with making it work with some external data providers.

The situation we're in is that instead of calling out directly to REST APIs, we need to build the datasource from open source SDKs.

i.e.
for a particular user, on each GraphQL request (and continuing for the duration of that request across resolvers), we need to fetch some access_tokens/refresh_tokens from the database and initialize an SDK with those values.

const authInfo = await db.fetchAndDecryptTokens(user.id)
const provider = new Provider(authInfo);

provider.fetchSomeDatas();

We thought it would be super cool to use datasources so every resolver didn't have to do this setup code.

One problem we have is that the DataSource initialize method is synchronous so we can't do the async setup before we add that class to the dataSources provider as part of the ApolloServer constructor. Additionally, we don't have the context passed to the initialize method so we don't know who the user is at that point anyway.

Another problem is that we would ideally only initialize a particular data source if the user is querying the part of the schema that needs those types. For example, we have two data providers: Salesforce and Mailchimp. For MailChimp queries, ideally we wouldn't look up and provide the Salesforce auth credentials as they are not needed.

What we've come up with as a workaround is:

export class EmailMarketingDataSource {
  private context: any;
  private token: string;
  private client: MailchimpClient;

  public initialize({ context }) {
    this.context = context;
    this.getToken(); // lazy kick off token fetching
  }

  public async authenticate(userId) {
    if (!this.token) {
      await this.getToken();
    }

    this.client = new MailchimpClient(this.token);
  }

  private getToken() {
    getUserToken(this.context.user.userId).then(
      ({ token }) => (this.token = token)
    );
  }
}

QUESTION:
Is there a way to lazy initialize data sources using the data source pattern, but without having to do some of the (probably weird) stuff we're doing in our class?

馃К data-sources

Most helpful comment

Async initialize would be very useful for custom datasources, e.g. connecting to a database

All 3 comments

Async initialize would be very useful for custom datasources, e.g. connecting to a database

+1 for async initialization

I think this is fixed by #3639

Was this page helpful?
0 / 5 - 0 ratings