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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[apollo-datasource-rest] - "TypeError cannot read property of 'fetch' of undefined" #2240

Closed
markcdev opened this issue Jan 29, 2019 · 13 comments

Comments

@markcdev
Copy link

Node - 10.15.0
Typescript - 3.1.2
apollo-datasource-rest - 0.1.5

I have a very simple data source class that extends the RESTDataSource class and makes a GET call to the star wars api. However at run time I'm getting the following error - "TypeError cannot read property fetch of undefined" which is located from line 148 in the RESTDataSource.js file on the following line -

const response = yield this.httpCache.fetch(...

@markcdev
Copy link
Author

AH! I for some reason node-fetch wasn't included as a dependency! please close, sorry.

@jplock
Copy link

jplock commented Feb 25, 2019

I just ran into this and had to call initialize(config) in the constructor to initialize the HTTPCache:

class MyAPI extends RESTDataSource {
  constructor(config) {
    super();
    this.initialize(config);
  }
}

@abernix
Copy link
Member

abernix commented Feb 25, 2019

@jplock What version of Apollo Server were you using that Data Source with? Did you have that data source declared in the dataSources property of the ApolloServer constructor? The initialize function is called automatically, so you shouldn't need to call it explicitly:

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({
context,
cache: requestContext.cache,
});
}
}

@jplock
Copy link

jplock commented Feb 25, 2019

@abernix we're using apollo-server-lambda v2.4.3 and we did have the data sources declared. I was trying to test the data source independently of Apollo (unit tests), and I had to execute initialize() for my unit tests.

@abernix
Copy link
Member

abernix commented Feb 25, 2019

Aha, that makes sense. Since DataSources intentionally don't call initialize and, as I demonstrated above, are only initialized by the server itself, you would need to call initialize manually in your case. I would advise calling .initialize directly, not adding it to the constructor as you've done above, but I would strongly recommend testing the datasources using createTestClient as seen in that guide on testing from the server docs, which actually has an example for testing RESTDataSources.

I'll close this, but happy to assist further if I can be of help.

@mrdulin
Copy link

mrdulin commented Jun 4, 2019

Hit this issue.

After reading @abernix 's explain. Here is my case:

I don't inject my application datasources to ApolloServer directly. Because I think dataSource like DAO. Instead of injecting to ApolloServer dataSources, I inject my datasources to service layer, the business logic layer. The code like this:

  const context = {} as ApplicationContext;
  const cache = new InMemoryLRUCache();
  const httpDataSourceConfig: DataSourceConfig<ApplicationContext> = { context, cache };

  const customerDataSource = new CustomerDataSourceImpl(googleAdwordsDataSourceOptions);
  customerDataSource.initialize(httpDataSourceConfig);
  const managedCustomerDataSource = new ManagedCustomerDataSourceImpl({
    baseURL: `https://us-central1-${process.env.GOOGLE_CLOUD_PROJECT}.cloudfunctions.net/`,
  });
  managedCustomerDataSource.initialize(httpDataSourceConfig);


const managedCustomerService = new ManagedCustomerService({
          managedCustomerDataSource,
          googleAccountDataSource,
          userDataSource,
          googleAdwordsDataSource,
        }),

And, I inject these serivces to Apollo context.

If you don't call initialize method when you use dataSource outside which means you don't inject datasource to dataSources configuration of ApolloServer, it will throw TypeError cannot read property of 'fetch' of undefined.

P.S. You can use some IoC implements the DIP, instead of using new keyword, but this is another topic.

@mImranAziz
Copy link

In my case error was in ~\node_modules\apollo-datasource-rest\src\RESTDataSource.ts,

line await this.httpCache.fetch(request

I resolved this by initializing httpCache as:

constructor() {
super();
this.baseURL = v6url;
this.httpCache = new HTTPCache()
}

So it's not null.

@abernix
Copy link
Member

abernix commented Jul 4, 2019

@mImranAziz DataSources have their initialize method called automatically by Apollo Server if they are declared in the dataSources Array of the ApolloServer constructor options:

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

The default cache should be set to an InMemoryLRUCache if you haven't specified a top-level cache yourself:

if (!requestOptions.cache) {
requestOptions.cache = new InMemoryLRUCache();
}

Do any of these things sound possible? Your workaround shouldn't be necessary.

@esemeniuc
Copy link

esemeniuc commented Aug 7, 2019

@abernix I also needed to use @mImranAziz fix. Running apollo server 2.8.1 as well.

My solution was to not override initialize(config) since that prevents the abstract method from running this.httpCache = new HTTPCache(config.cache, this.httpFetch);

@linteck
Copy link

linteck commented Jan 23, 2020

@abernix Why does "DataSources have their initialize method called automatically by Apollo Server"? Is it necessary? Why not put the initializer() into the constructor? Or at least write this trick into document.

@wzup
Copy link

wzup commented Mar 11, 2020

@abernix
Somehow this is not true.
If you do not call initialize directly, it is never set auto-magically.

@wzup
Copy link

wzup commented Mar 11, 2020

@markcdev

AH! I for some reason node-fetch wasn't included as a dependency! please close, sorry.

And what does it mean? What actions are you expecting from us after your AH!-answer?

@robe007
Copy link

robe007 commented Sep 17, 2020

I had the same problem with apollo-datasource-rest combined with graphql-yoga, but I was able to get it work.

You can see my comments about it here

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

9 participants