Apollo-link: Utiliser node-fetch avec apollo-link-http

Créé le 21 févr. 2018  ·  49Commentaires  ·  Source: apollographql/apollo-link


L'utilisation de HttpLink avec node-fetch donne l'erreur suivante

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

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

Résultat escompté :
Selon la documentation, ce qui précède aurait dû être compilé.

Résultat réel :

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);

Comment reproduire le problème :
Les versions suivantes sont utilisées pour écrire le code ci-dessus.

    "@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"


Utilisez les versions ci-dessus et créez l'instance de HttpLink en tapuscrit pour voir l'erreur ci-dessus.

Commentaire le plus utile

(Suivi du 7 mai 2018 : cross-fetch est désormais fourni avec des définitions de type TypeScript)

cross-fetch n'a pas encore été livré avec les définitions de type TypeScript (ni @DefinitelyTyped).

En attendant la fusion de lquixada/cross-fetch#12 cross-fetch est une alternative, j'ai trouvé que isomorphic-fetch fonctionnait bien avec HttpLink dans TypeScript à partir de maintenant :

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

const link = new HttpLink({
  fetch
})

Tous les 49 commentaires

Que se passe-t-il si vous utilisez createHttpLink au lieu de new HttpLink ?

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

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

@dejayc Cela donne la même erreur lorsque createHttpLink est utilisé.

En fait, j'ai compris le problème. Le node-fetch 2.x n'est pas compatible avec _apollo-link_. La signature de _fetch_ est différente.

Le node-fetch 2.x n'est pas compatible avec apollo-link. La signature de fetch est différente.

Ah, je suppose que vous pouvez le frapper.

Je suis tombé sur ce problème aujourd'hui dans mon application isomorphe. Je ne suis pas tout à fait d'accord avec le fait que l'extraction globale soit la solution de secours par défaut, en particulier de nos jours avec SSR, mais au moins l'erreur était quelque peu 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';

Ma solution consistait soit à utiliser conditionnellement node-fetch ou whatwg-fetch fonction de l'environnement nœud/navigateur. Ou utilisez simplement cross-fetch qui fait fondamentalement la même chose.

Donc...

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

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

@jmca La façon dont vous avez suggéré pour TypeScript a fonctionné pour moi ! Merci!!

J'ai rencontré ce problème aujourd'hui et j'ai découvert que nous ne sommes pas compatibles avec node-fetch v2, je pense que nous devrions résoudre ce problème.

Je commence à utiliser cross-fetch maintenant mais il importe juste un fetch: any ...

(Suivi du 7 mai 2018 : cross-fetch est désormais fourni avec des définitions de type TypeScript)

cross-fetch n'a pas encore été livré avec les définitions de type TypeScript (ni @DefinitelyTyped).

En attendant la fusion de lquixada/cross-fetch#12 cross-fetch est une alternative, j'ai trouvé que isomorphic-fetch fonctionnait bien avec HttpLink dans TypeScript à partir de maintenant :

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

const link = new HttpLink({
  fetch
})

La documentation npmjs.com encourage les utilisateurs à utiliser node-fetch mais ne précise pas quelle version. Comment pouvons-nous mettre à jour cette documentation?

Remarque : l'utilisation de whatwg-fetch est une solution de contournement viable.

Y a-t-il eu un mouvement à ce sujet?

L'utilisation de cross-fetch semble être une solution de contournement étrange car elle utilise simplement node-fetch . N'est-ce pas vraiment un problème ?

whatwg-fetch n'est pas une solution de contournement pour ceux d'entre nous du côté serveur.

Si quelqu'un ouvre un PR qui inclut les bonnes définitions de type qui fonctionneront avec toutes les implémentations de récupération mais maintient une vérification de type, s'il vous plaît @stubailo moi et j'essaierai de fusionner !

@stubailo Sur Apollo serveur nous utilisons ce dans le cadre de apollo-server-env .

l'utilisation de HttpLink est facultative, cela fonctionne pour moi :

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

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

Des nouvelles à ce sujet ? node-fetch pose toujours des problèmes avec apollo-link et TS.

Des nouvelles? Toujours des problèmes avec node-fetch

Une solution de contournement consiste à ne pas installer @types/node-fetch et à le définir manuellement comme GlobalFetch vous-même.

Pour ce faire, ajoutez ce qui suit à n'importe quel fichier .d.ts de votre projet ;

// 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;
}

Vous pouvez simplement utiliser un truc de coercition de type as ...

Bien sûr, mais quel est l'intérêt d'installer les types, si vous allez juste les forcer à passer à autre chose de toute façon?
Autant utiliser ma solution dans ce cas.

Désolé, j'ai mal lu ce que vous faisiez, ignorez mon commentaire précédent.

Cependant, cela vous oblige à modifier votre tsconfig pour cibler le navigateur, car GlobalFetch n'est fourni que si vous avez "dom" comme entrée dans le champ "lib": https://github.com/apollographql/apollo-link/issues/ 273#issuecommentaire -347878009

Deuxièmement, au lieu de modifier manuellement un .d.ts , ne pourriez-vous pas simplement passer GlobalFetch['fetch'] au constructeur HTTPLink ? Cela le rend beaucoup moins caché.

  1. Bien sûr, mais pour vous conformer à la saisie de HttpLink, vous devez utiliser GlobalFetch['fetch'] malgré tout, donc je ne vois aucun moyen de contourner cette exigence.

  2. Je ne suis pas. GlobalFetch['fetch'] est un type, pas une variable.
    Voulez-vous dire importer le node-fetch puis le transtyper en GlobalFetch['fetch'] ?
    Ce n'est pas une option pour moi car j'ai activé noImplictAny dans mes projets, donc je ne peux rien importer qui n'a pas de définition.

C'est juste une solution de contournement qui fonctionne pour moi 🤷‍♀️, mais je me rends compte que c'est loin d'être parfait (mot clé : _workaround_).

Je pense qu'une bonne solution serait de simplement changer la saisie en une union de GlobalFetch['fetch'] et le type par défaut d'exportation de node-fetch.
Ou remplacez simplement la bibliothèque recommandée par une bibliothèque de récupération de nœuds conforme à GlobalFetch['fetch'] (whatwg-fetch ou autre).

  1. Ah, je ne savais pas que c'était nécessaire. TIL.

  2. Désolé, j'ai juste une journée de congé. Tu as raison, c'est un type, pas une variable.

https://www.npmjs.com/package/whatwg-fetch indique assez explicitement que "Ce projet ne fonctionne pas dans les environnements Node.js. Il est destiné uniquement aux navigateurs Web. Vous devez vous assurer que votre application n'essaie pas de package et exécutez-le sur le serveur."

Oui, quelqu'un devrait vraiment corriger le bogue correctement en corrigeant les types.

Après un examen plus approfondi, cela semble être principalement un problème avec node-fetch , j'ai donc ouvert le problème ci-dessus. Il est tout à fait possible qu'ils nous disent de simplement changer nos types, cependant.

D'accord, node-fetch semble nous dire de simplement changer nos types. Un hack serait d'importer les types de node-fetch et de l'ajouter comme solution de contournement ?

@grantwwu Désolé, les choses sont assez mouvementées dans le déroulement de GraphQL Summit, mais nous avons récemment commencé à utiliser un package apollo-env qui réexporte node-fetch avec les bons types : https://github .com/apollographql/apollo-tooling/tree/master/packages/apollo-env

(Nous voudrons probablement séparer les exportations mondiales de récupération cependant)

Je viens de faire un import { fetch } from 'apollo-env' et j'obtiens _toujours_ des erreurs TypeScript lorsque je le transmets au constructeur HttpLink .

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]'.

J'ai réussi à faire fonctionner ceci dans mon test:

import { fetch } from 'apollo-env'

......

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

ça ne marche toujours pas chez moi :/

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 quelles versions d'apollo-http-link et apollo-env avez-vous utilisées ? Aussi, c'est avec node, non?

Oui le même ici. L'utilisation d'apollo-env ne résout pas le problème pour moi.

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]

@grantwwu : j'utilise
"apollo-client": "^2.4.12",
"apollo-env": "^0.3.2",
"apollo-link-http": "^1.5.9",

J'utilise fil pour la gestion des dépendances dans mon application

Je suis passé à graphql-request pour mon projet.

@jacobtani A quoi ressemble votre tsconfig ?

apollo-env est toujours différent de ce que HttpLink attend. le paramètre d'entrée ne devrait pas être requis

J'ai fini par le remplacer comme ça et ça a fonctionné

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

J'utilise ceci à partir du nœud en utilisant ceci

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

VEUILLEZ CORRIGER L'ÉQUIPE DOCS APOLLO ! Ce problème date de plus d'un an

@rlancer Je suppose que c'est le cas car, comme mentionné ci-dessus dans votre commentaire, il n'est pas encore corrigé car apollo-env besoin d'un correctif. Ce n'est pas dans ce référentiel mais dans le référentiel apollo-tooling .

@JoviDeCroock Il existe des solutions qui fonctionnent, les documents doivent indiquer de les utiliser par opposition à une solution qui échoue et oblige les utilisateurs à rechercher des solutions de contournement.

@JoviDeCroock apollo-env et apollo-tooling ont la même déclaration de types d'extraction et les deux sont différents du Global['fetch'] attendu par HttpLink. Mais cela ne semble pas être le problème, si je déclare le module moi-même avec la même déclaration que apollo-env il ne se plaint pas des types. Peut-être que l'exportation ne fonctionne pas

Eh bien, personnellement, je ne les utilise jamais. Si vous pouvez m'indiquer une solution, je serais ravi de pr

Je suppose qu'en faisant de ces 2 types la même chose devrait fonctionner.

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

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

@jmca Merci mec, vous m'avez sauvé la journée, j'ai eu un problème avec la tête qui n'est pas défini dans le nouveau createUploadLink lors de l'utilisation des tests de plaisanterie.

@tafelito Merci pour votre solution, elle a été très utile, mais je pense que la véritable erreur a été trouvée et qu'elle est due à la nouvelle mise à jour de TypeScript. Dans sa version 3.6, GlobalFetch est supprimé et WindowOrWorkerGlobalScope est utilisé à la place, cela nous oblige donc à fermer la version dans nos dépendances du package.json "typescript": "3.5.1" .

voici le lien

Pour faire écho au commentaire ci-dessus, mon repo doit s'en tenir au dactylographié v3.5.3

Je suppose qu'en faisant de ces 2 types la même chose devrait fonctionner.

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

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

J'ai pu le réparer en utilisant uniquement la deuxième partie, merci @tafelito

même problème.

"@types/node-fetch": "^2.5.0",
 "typescript": "^3.5.1"
"node-fetch": "^2.6.0",
error TS2345: Argument of type '{ uri: string; fetch: typeof fetch; }' is not assignable to parameter of type 'Options'.
  Types of property 'fetch' are incompatible.
    Type 'typeof fetch' 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 'import("/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/@types/node-fetch/index").RequestInfo'.
          Type 'Request' is not assignable to type 'RequestInfo'.
            Type 'Request' is missing the following properties from type 'Request': context, compress, counter, follow, and 6 more.

8 const link = new HttpLink({ uri: 'http://localhost:3000', fetch });

J'ai le même problème dans mon application. Je résous le casting à any comme ça :

import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-boost'
import { createHttpLink } from 'apollo-link-http'
import fetch from 'node-fetch'

const httpLink = createHttpLink({
//ISSUE: https://github.com/apollographql/apollo-link/issues/513
fetch: fetch as any,
uri: 'https://api.graph.cool/simple/v1/swapi',
})

const client = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
})

export default client

en fin de compte, le problème est que les node-fetch et les typages associés s'écartent intentionnellement de la spécification :

// copied directly from the @types/node-fetch
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node-fetch/index.d.ts
Request {
   ...
    // node-fetch extensions to the whatwg/fetch spec
    agent?: Agent | ((parsedUrl: URL) => Agent);
    compress: boolean;
    counter: number;
    follow: number;
    hostname: string;
    port?: number;
    protocol: string;
    size: number;
    timeout: number;

les erreurs du compilateur sont donc inévitables si vous ne transposez pas ou ne créez pas de nouvelles saisies qui omettent ces ajouts.

j'ai choisi de downcast node-fetch :

import nodeFetch from 'node-fetch'
import { WhatWgFetch } from '../src/interfaces' // export type WhatWgFetch = typeof fetch
const fetch = (nodeFetch as unknown) as WhatWgFetch

ce n'est pas génial, mais node-fetch != fetch, qui ... grogne... est trompeur. node-fetch-like aurait peut-être été plus approprié, et laisser les extensions _out_ dans l'implémentation de base de node-fetch pour maintenir la conformité de node-fetch aurait rendu service à ceux comme nous :)

Cela peut être complètement hors de propos... mais... j'ai eu le même problème depuis environ un jour... seulement pour se rendre compte que "récupérer" est quelque chose qui est disponible dans le navigateur, mais pas côté serveur. Si votre application va chercher à partir du navigateur, il est en quelque sorte inutile de pré-afficher la connexion côté serveur.

Dans mon cas, en utilisant NextJS, j'ai modifié le composant qui nécessitait que le lien http ne soit https://nextjs.org/docs#with -no-ssr

J'avais le même problème, au lieu d'installer node-fetch et @types/node-fetch je suis allé directement avec apollo-env et bam! toutes les erreurs disparues !

J'ai réussi à faire fonctionner cela avec isomorphic-fetch

package.json (toutes les versions sélectionnées pour la compatibilité avec celle utilisée par appsync)
    "apollo-link": "1.2.3",
    "apollo-link-context": "1.0.9",
    "apollo-link-http": "1.3.1",
    "aws-appsync": "^3.0.2",
    "isomorphic-fetch": "^2.2.1",
...
    "@types/isomorphic-fetch": "0.0.35",
.../typings/index.d.ts
declare function fetch(
  input?: RequestInfo,
  init?: RequestInit
): Promise<Response>;

declare interface GlobalFetch {
  fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
}
tsconfig.json
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "lib": [ "dom",  "es6",  "esnext.asynciterable" ]
     ...
   },
  "types": [  "node", "aws-sdk"  ],
  "include": [ "./src/**/*.ts" ],
...
code
import * as fetch from 'isomorphic-fetch';

const client = new AWSAppSyncClient(appSyncClientOptions, {
        link: createAppSyncLink({
          ...appSyncClientOptions,
          resultsFetcherLink: ApolloLink.from([
            createHttpLink({
              fetch: fetch as GlobalFetch['fetch'],
              uri: appSyncClientOptions.url
            })
          ])
        })
      });

Considérez cross-fetch !

Cela fonctionne avec dactylographié et nœud (pas de navigateur).

import fetch from 'cross-fetch'

const httpLink = new HttpLink({
  uri: "<your-uri>",
  fetch,
})
Cette page vous a été utile?
0 / 5 - 0 notes