Apollo-client: run apollo-client in node environment throws error.

Created on 13 Jun 2018  ·  6Comments  ·  Source: apollographql/apollo-client

Intended outcome:
execute normally in node environment.

Actual outcome:
throw error:

fetch is not found globally and no fetcher passed, to fix pass a fetch for
your environment like https://www.npmjs.com/package/node-fetch.

How to reproduce the issue:

// create a new ts project and typings follow
import gql from 'graphql-tag';
import ApolloClient from 'apollo-boost';
import fetch from 'node-fetch';

const uri = 'https://w5xlvm3vzz.lp.gql.zone/graphql';
const client = new ApolloClient({
    uri,
    fetchOptions: {
        fetch: fetch as any
    }
});

client
    .query({
        query: gql`
            {
                rates(currency: "USD") {
                    currency
                }
            }
        `
    })
    .then(result => console.log(result));

execute:

ts-node src/index.ts

Versions
"dependencies": {
"apollo-boost": "^0.1.8",
"graphql": "^0.13.2",
"graphql-tag": "^2.9.2",
"node-fetch": "^2.1.2",
"react-apollo": "^2.1.4"
},
"devDependencies": {
"@types/node-fetch": "^2.1.1"
}

code error
it seems that is a code error in apollo-boost.

in apollo-boost/src/index.ts, DefaultClient call new HttpLink(xxx) to create a HttpLink:

    const httpLink = new HttpLink({
      uri: uri || '/graphql',
      fetchOptions: fetchOptions || {},
      credentials: credentials || 'same-origin',
      headers: headers || {},
    });

and HttpLink is defined in apollo-link-http, which calls createHttpLink:

export class HttpLink extends ApolloLink {
  public requester: RequestHandler;
  constructor(opts?: HttpLink.Options) {
    super(createHttpLink(opts).request);
  }
}

in createHttpLink it will access fetch in param:

export const createHttpLink = (linkOptions: HttpLink.Options = {}) => {
  let {
    uri = '/graphql',
    // use default global fetch is nothing passed in
    fetch: fetcher,
    includeExtensions,
    useGETForQueries,
    ...requestOptions
  } = linkOptions;

  // dev warnings to ensure fetch is present
  checkFetcher(fetcher);
  // omit other code
}

fetch does exists in linkOptions but exists in linkOptions.fetchOptions, so fetcher is undefined ans call checkFetcher(fetcher); throws error.

good-first-issue ✔ confirmed 🏃‍♂️ medium-priority 🐞 bug 🙏 help-wanted

Most helpful comment

Thanks @forclan - this is actually working as designed, but it is definitely a bit confusing. Apollo Boost doesn't let you set a fetch (as you've found out, passing one in via fetchOptions won't work). For now your best bet is to eject from apollo-boost, and use the full apollo-client instead. Then when you define your HttpLink, you can properly set the fetch option.

I've marked this as a bug though since apollo-boost should work on the server, and allow a custom fetcher to be defined. If anyone is interested in adjusting boost to accept a fetch param, which will the be passed into the HttpLink instance, that would be awesome!

All 6 comments

Thanks @forclan - this is actually working as designed, but it is definitely a bit confusing. Apollo Boost doesn't let you set a fetch (as you've found out, passing one in via fetchOptions won't work). For now your best bet is to eject from apollo-boost, and use the full apollo-client instead. Then when you define your HttpLink, you can properly set the fetch option.

I've marked this as a bug though since apollo-boost should work on the server, and allow a custom fetcher to be defined. If anyone is interested in adjusting boost to accept a fetch param, which will the be passed into the HttpLink instance, that would be awesome!

@hwillson I'm happy to take that one. Just tell me, the current behaviour is expected (in the browser) but you're suggesting to add fetch as a param to ApolloBoost then should I somehow check if we're running it in the browser/node.js environment and only allow it on node.js env or just simply add fetch param regardless of environment?

Sorry for the delay @mbaranovski - I meant add the fetch param regardless (which you've done in your PR). Thanks!

I'will close the issue since code is merged.

@hwillson Do we have to specify the fetch param? Can't we just use a global unfetch polyfill

@borisyordanov unfetch is for js in browser, there we use it. In node.js, we need to pass a fetch lib like node-fetch.

Was this page helpful?
0 / 5 - 0 ratings