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

Using node-fetch with apollo-link-http #513

Open
yogeshsajanikar opened this issue Feb 21, 2018 · 39 comments

Comments

Projects
None yet
@yogeshsajanikar
Copy link

commented Feb 21, 2018

Using HttpLink with node-fetch gives following error

import { HttpLink } from 'apollo-link-http';
import fetch from 'node-fetch';

const link = new HttpLink({
      fetch,
      uri: this.endPoint.toString(),
    });

Intended outcome:
According to the documentation the above should have compiled.

Actual outcome:

src/tw-algo-manager.ts:20:31 - error TS2345: Argument of type '{ fetch: (url: string | Request, init?: RequestInit | undefined) => Promise<Response>; uri: strin...' is not assignable to parameter of type 'Options | undefined'.
  Type '{ fetch: (url: string | Request, init?: RequestInit | undefined) => Promise<Response>; uri: strin...' is not assignable to type 'Options'.
    Types of property 'fetch' are incompatible.
      Type '(url: string | Request, init?: RequestInit | undefined) => Promise<Response>' is not assignable to type '((input: RequestInfo, init?: RequestInit | undefined) => Promise<Response>) | undefined'.
        Type '(url: string | Request, init?: RequestInit | undefined) => Promise<Response>' is not assignable to type '(input: RequestInfo, init?: RequestInit | undefined) => Promise<Response>'.
          Types of parameters 'url' and 'input' are incompatible.
            Type 'RequestInfo' is not assignable to type 'string | Request'.
              Type 'Request' is not assignable to type 'string | Request'.
                Type 'Request' is not assignable to type 'Request'. Two different types with this name exist, but they are unrelated.
                  Property 'context' is missing in type 'Request'.

20     const link = new HttpLink({
                                 ~21       fetch,
   ~~~~~~~~~~~~22       uri: this.endPoint.toString(),
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~23     }); // const link = createHttpLink(linkOptions);

How to reproduce the issue:
Following versions are used to write above code.

    "@types/graphql": "^0.12.4",
    "@types/node-fetch": "^1.6.7",
    "apollo-cache-inmemory": "^1.1.9",
    "apollo-client": "^2.2.5",
    "apollo-link": "^1.2.0",
    "apollo-link-http": "^1.4.0",
    "graphql": "^0.13.1",
    "graphql-tag": "^2.8.0",
    "node-fetch": "^1.7.2",
    "react-apollo": "^2.0.4",
    "url": "^0.11.0"

Use the above versions and create the instance of HttpLink in typescript to see the above error.

@dejayc

This comment has been minimized.

Copy link

commented Feb 23, 2018

What happens if you use createHttpLink instead of new HttpLink?

import { createHttpLink } from 'apollo-link-http';
import fetch from 'node-fetch';

const link = createHttpLink({
      fetch,
      uri: this.endPoint.toString(),
    });
@yogeshsajanikar

This comment has been minimized.

Copy link
Author

commented Feb 23, 2018

@dejayc It gives same error when createHttpLink is used.

Actually, I figured out the problem. The node-fetch 2.x is not compatible with apollo-link. The signature of fetch is different.

@dejayc

This comment has been minimized.

Copy link

commented Feb 23, 2018

The node-fetch 2.x is not compatible with apollo-link. The signature of fetch is different.

Ah, I guess you can duck punch it.

@jmca

This comment has been minimized.

Copy link

commented Feb 24, 2018

I came across this issue today in my isomorphic app. I don't totally agree with global fetch being the default fallback especially in these days of SSR, but at least the error was somewhat informative:

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

For example:
import fetch from 'nodefetch';
import { createHttpLink } from 'apollo-link-http';

My solution was either to conditionally usenode-fetch or whatwg-fetch depending on the node/browser environment. Or just use cross-fetch which basically does the same thing.

So...

// Using TypeScript
import * as fetch from 'cross-fetch'
new HttpLink({ fetch })

// Or just...
// import 'cross-fetch/polyfill'
@julianguyen

This comment has been minimized.

Copy link

commented Mar 6, 2018

@jmca The way you suggested for TypeScript worked for me! Thanks!!

@huan

This comment has been minimized.

Copy link

commented Mar 7, 2018

I ran into this issue today, and find out we are not compatible with node-fetch v2, I believe we should fix this.

I start using cross-fetch now but it just imports a fetch: any...

@wongmjane

This comment has been minimized.

Copy link

commented Apr 26, 2018

(Follow up on May 7, 2018: cross-fetch now comes with TypeScript type definitions)

cross-fetch has not shipped with TypeScript type definitions yet (nor does @DefinitelyTyped).

While waiting for lquixada/cross-fetch#12 to be merged cross-fetch is an alternative, I found isomorphic-fetch working alright with HttpLink in TypeScript as of now:

import { HttpLink } from 'apollo-boost'
import fetch from 'isomorphic-fetch'

const link = new HttpLink({
  fetch
})
@gardner

This comment has been minimized.

Copy link

commented Apr 29, 2018

The npmjs.com documentation encourages users to use node-fetch but doesn't specify which version. How can we update that documentation?

Note: using whatwg-fetch is a viable workaround.

@grantwwu

This comment has been minimized.

Copy link

commented Jul 27, 2018

Has there been any movement on this?

Using cross-fetch seems like a strange workaround since it just uses node-fetch. Is that not actually a problem?

whatwg-fetch is not a workaround for those of us on the server side.

@stubailo

This comment has been minimized.

Copy link
Member

commented Aug 10, 2018

If someone opens a PR that includes the right type definitions that will work with all of the fetch implementations but maintains some type checking, please @stubailo me and I'll try to merge!

@martijnwalraven

This comment has been minimized.

Copy link
Contributor

commented Aug 11, 2018

@stubailo On Apollo Server we use this as part of apollo-server-env.

@jaaaco

This comment has been minimized.

Copy link

commented Aug 24, 2018

using HttpLink is optional, this works for me:

import ApolloClient from 'apollo-boost'
import 'isomorphic-fetch'

const client = new ApolloClient({
  uri: 'endpoint-url-here'
})
@moimael

This comment has been minimized.

Copy link

commented Sep 17, 2018

Any news on this ? node-fetch still causes issues with apollo-link and TS.

@XBeg9

This comment has been minimized.

Copy link

commented Oct 30, 2018

Any news? Still getting issues with node-fetch

@jariz

This comment has been minimized.

Copy link

commented Nov 1, 2018

A workaround for this is to not install @types/node-fetch and manually define it as GlobalFetch yourself.

To do this, add the following to any .d.ts file in your project;

// real node-fetch types clash with apollo-link-http, so manually define it as globalfetch here.
declare module 'node-fetch' {
    const fetch: GlobalFetch['fetch'];
    export default fetch;
}
@grantwwu

This comment has been minimized.

Copy link

commented Nov 1, 2018

You can just use an as type coercion thing...

@jariz

This comment has been minimized.

Copy link

commented Nov 1, 2018

Sure but what is the point of installing the types at all, if you're just gonna force cast it to something else eitherway?
Might as well use my solution in that case.

@grantwwu

This comment has been minimized.

Copy link

commented Nov 1, 2018

Sorry, I misread what you were doing, ignore my previous comment.

However, this requires you modify your tsconfig to target the browser, as GlobalFetch is only provided if you have "dom" as an entry in the "lib" field: #273 (comment)

Secondly, instead of manually modifying a .d.ts, couldn't you just pass GlobalFetch['fetch'] to the HTTPLink constructor? That makes it a lot less hidden.

@jariz

This comment has been minimized.

Copy link

commented Nov 1, 2018

  1. Sure, but to conform to HttpLink's typing you have to use GlobalFetch['fetch'] regardless so I see no way around that requirement.

  2. I don't follow. GlobalFetch['fetch'] is a type, not a variable.
    Do you mean importing node-fetch and then casting it to GlobalFetch['fetch']?
    That's not on option for me as I have noImplictAny enabled in my projects so I can't import anything that doesn't have a definition.

It's just a workaround that works for me 🤷‍♀️, but I realise it's far from perfect (keyword: workaround).

I think a good solution would be to just change the typing to a union of GlobalFetch['fetch'] and the default type of node-fetch's export.
Or just change the recommended library to a node fetch lib that DOES conform to GlobalFetch['fetch'] (whatwg-fetch or whatever).

@grantwwu

This comment has been minimized.

Copy link

commented Nov 1, 2018

  1. Ah, I didn't realize that was required. TIL.

  2. Sorry, I'm just having a really off day. You're right, that's a type, not a variable.

https://www.npmjs.com/package/whatwg-fetch states pretty explicitly that "This project doesn't work under Node.js environments. It's meant for web browsers only. You should ensure that your application doesn't try to package and run this on the server."

Yes, someone really ought to fix the bug properly by fixing the types.

@grantwwu

This comment has been minimized.

Copy link

commented Nov 1, 2018

Upon further review, this seems to be mainly a problem with node-fetch, so I opened the above issue. It's entirely possible that they will tell us to just change our types, however.

@grantwwu

This comment has been minimized.

Copy link

commented Nov 6, 2018

Okay, node-fetch seems to be telling us to just change our types. One hack would be to import node-fetch's types and to add that as a workaround?

@martijnwalraven

This comment has been minimized.

Copy link
Contributor

commented Nov 6, 2018

@grantwwu Sorry, things are pretty hectic in the rundown to GraphQL Summit, but we've recently started using an apollo-env package that re-exports node-fetch with the right types: https://github.com/apollographql/apollo-tooling/tree/master/packages/apollo-env

@martijnwalraven

This comment has been minimized.

Copy link
Contributor

commented Nov 6, 2018

(We'll probably want to separate out the global fetch exports though)

@Siyfion

This comment has been minimized.

Copy link

commented Dec 12, 2018

I've just done an import { fetch } from 'apollo-env' and I'm still getting TypeScript errors when passing it into the HttpLink constructor.

TSError: ⨯ Unable to compile TypeScript:
src/index.ts(20,31): error TS2345: Argument of type '{ uri: string; fetch: (input?: string | Request | undefined, init?: RequestInit | undefined) => Promise<Response>; }' is not assignable to parameter of type 'Options'.
  Types of property 'fetch' are incompatible.
    Type '(input?: string | Request | undefined, init?: RequestInit | undefined) => Promise<Response>' is not assignable to type '(input: RequestInfo, init?: RequestInit | undefined) => Promise<Response>'.
      Types of parameters 'input' and 'input' are incompatible.
        Type 'RequestInfo' is not assignable to type 'string | Request | undefined'.
          Type 'Request' is not assignable to type 'string | Request | undefined'.
            Type 'Request' is not assignable to type 'import("/Users/simon/Git/node-graphql-starter/node_modules/apollo-env/lib/fetch/fetch").Request'.
              Types of property 'headers' are incompatible.
                Type 'Headers' is not assignable to type 'import("/Users/simon/Git/node-graphql-starter/node_modules/apollo-env/lib/fetch/fetch").Headers'.
                  Types of property 'values' are incompatible.
                    Type '() => IterableIterator<string>' is not assignable to type '() => Iterator<[string]>'.
                      Type 'IterableIterator<string>' is not assignable to type 'Iterator<[string]>'.
                        Types of property 'next' are incompatible.
                          Type '{ (value?: any): IteratorResult<string>; (value?: any): IteratorResult<string>; }' is not assignable to type '{ (value?: any): IteratorResult<[string]>; (value?: any): IteratorResult<[string]>; }'.
                            Type 'IteratorResult<string>' is not assignable to type 'IteratorResult<[string]>'.
                              Type 'string' is not assignable to type '[string]'.
@jacobtani

This comment has been minimized.

Copy link

commented Feb 7, 2019

I managed to get this to work in my test:

import { fetch } from 'apollo-env'

......

function httpLink({ apiUrl, idToken }) {
  return new HttpLink({
    uri: apiUrl,
    headers: {
      authorization: `Bearer ${idToken}`,
    },
    fetch
  })
}
@grantwwu

This comment has been minimized.

Copy link

commented Feb 8, 2019

It's still not working for me :/

src/remoteSchemas.ts:54:45 - error TS2322: Type '(input?: RequestInfo, init?: RequestInit) => Promise<Response>' is not assignable to type '(input: RequestInfo, init?: RequestInit) => Promise<Response>'.
  Types of parameters 'input' and 'input' are incompatible.
    Type 'RequestInfo' is not assignable to type 'import("/Users/grant.wu/petuum/api-gateway/node_modules/apollo-env/lib/fetch/fetch").RequestInfo'.
      Type 'Request' is not assignable to type 'RequestInfo'.
        Type 'Request' is not assignable to type 'import("/Users/grant.wu/petuum/api-gateway/node_modules/apollo-env/lib/fetch/fetch").Request'.
          Types of property 'headers' are incompatible.
            Type 'Headers' is missing the following properties from type 'Headers': entries, keys, values, [Symbol.iterator]

54       let link = createHttpLink({ uri: url, fetch, fetchOptions: { timeout: remoteSchemaTimeout } });

@jacobtani which versions of apollo-http-link and apollo-env did you use? Also, this is with node, right?

@rahulthewall

This comment has been minimized.

Copy link

commented Feb 20, 2019

Yes, same here. Using apollo-env does not solve the issue for me.

Argument of type '{ credentials: string; fetch: (input?: string | Request | undefined, init?: RequestInit | undefined) => Promise<Response>; uri: string; }' is not assignable to parameter of type 'PresetConfig'.
  Types of property 'fetch' are incompatible.
    Type '(input?: string | Request | undefined, init?: RequestInit | undefined) => Promise<Response>' is not assignable to type '(input: RequestInfo, init?: RequestInit | undefined) => Promise<Response>'.
      Types of parameters 'input' and 'input' are incompatible.
        Type 'RequestInfo' is not assignable to type 'string | Request | undefined'.
          Type 'Request' is not assignable to type 'string | Request | undefined'.
            Type 'Request' is not assignable to type 'import("/Users/rahul/work/r3pi/vi-image-contours/node_modules/apollo-env/lib/fetch/fetch").Request'.
              Types of property 'headers' are incompatible.
                Type 'Headers' is missing the following properties from type 'Headers': entries, keys, values, [Symbol.iterator]
@jacobtani

This comment has been minimized.

Copy link

commented Feb 20, 2019

@grantwwu : I use
"apollo-client": "^2.4.12",
"apollo-env": "^0.3.2",
"apollo-link-http": "^1.5.9",

I use yarn for dependency management in my app

@rahulthewall

This comment has been minimized.

Copy link

commented Feb 20, 2019

I switched to graphql-request for my project.

@grantwwu

This comment has been minimized.

Copy link

commented Feb 20, 2019

@jacobtani What does your tsconfig look like?

@tafelito

This comment has been minimized.

Copy link

commented Feb 22, 2019

apollo-env is still different from what HttpLink expects. the input param should not be required

I ended up overriding it like this and it worked

declare module "apollo-env" {
  export function fetch(
    input: RequestInfo,
    init?: RequestInit,
  ): Promise<Response>;
}

I'm using this from node using this

"apollo-env": "^0.3.3"
"apollo-link-http": "^1.5.11"

@rlancer

This comment has been minimized.

Copy link

commented Feb 25, 2019

PLEASE PATCH THE DOCS APOLLO TEAM! This issue is over a year old

@JoviDeCroock

This comment has been minimized.

Copy link
Collaborator

commented Feb 25, 2019

@rlancer I assume this is the case because as mentioned above your comment, it is not fixed yet since apollo-env needs a patch. This is not in this repo but in the apollo-tooling repository.

@rlancer

This comment has been minimized.

Copy link

commented Feb 25, 2019

@JoviDeCroock There are solutions that work, docs should indicate to use them as opposed to one that fails and forces people to Google for workarounds.

@tafelito

This comment has been minimized.

Copy link

commented Feb 25, 2019

@JoviDeCroock both apollo-env and apollo-tooling has the same fetch types declaration and both are different from the Global['fetch'] that the HttpLink expects. But this doesn't seem to be the problem, if I declare the module myself with the same declaration as apollo-env it does not complain about types. Maybe the export is not working

@JoviDeCroock

This comment has been minimized.

Copy link
Collaborator

commented Feb 25, 2019

Well, I personally never use these. If you can point me to a solution I'd gladly pr

@tafelito

This comment has been minimized.

Copy link

commented Feb 25, 2019

I guess by making these 2 types the same should work.

declare function fetch(
  input?: RequestInfo, ---> remove ?
  init?: RequestInit
): Promise<Response>;

declare interface GlobalFetch {
  fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
}
@hariantara

This comment has been minimized.

Copy link

commented May 15, 2019

@jmca Thanks man, you saved my day, got head bang got problem self is undefined in new createUploadLink while using jest testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.