Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating DataSources generically #2299

Closed
dennis-johnson-dev opened this issue Feb 11, 2019 · 4 comments
Closed

Creating DataSources generically #2299

dennis-johnson-dev opened this issue Feb 11, 2019 · 4 comments

Comments

@dennis-johnson-dev
Copy link
Contributor

馃憢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?

@orinokai
Copy link

orinokai commented Jul 5, 2019

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

@brunocascio
Copy link

+1 for async initialization

@rintaun
Copy link

rintaun commented Jun 8, 2020

I think this is fixed by #3639

@glasser
Copy link
Member

glasser commented Oct 11, 2022

As stated above, this was fixed in #3639, but then we fixed it even more in Apollo Server 4 by removing the artificial distinction between "the part of the context value that is 'data sources'" and "the rest of the context value"; see https://www.apollographql.com/docs/apollo-server/migration/#datasources for details.

@glasser glasser closed this as completed Oct 11, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants