Apollo-link: Verwenden von Node-Fetch mit apollo-link-http

Erstellt am 21. Feb. 2018  ·  49Kommentare  ·  Quelle: apollographql/apollo-link


Die Verwendung von HttpLink mit Node-Fetch führt zu folgendem Fehler

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

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

Beabsichtigtes Ergebnis:
Laut der Dokumentation sollte das oben zusammengestellte sein.

Tatsächliches Ergebnis:

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

So reproduzieren Sie das Problem:
Die folgenden Versionen werden verwendet, um den obigen Code zu schreiben.

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


Verwenden Sie die obigen Versionen und erstellen Sie die Instanz von HttpLink in Typescript, um den obigen Fehler anzuzeigen.

Hilfreichster Kommentar

(Folgeaktion am 7. Mai 2018: cross-fetch jetzt TypeScript-Typdefinitionen)

cross-fetch wurde noch nicht mit TypeScript-Typdefinitionen ausgeliefert (und @DefinitelyTyped auch nicht).

Während ich darauf warte, dass lquixada/cross-fetch#12 zusammengeführt wird, ist cross-fetch eine Alternative, aber ich habe festgestellt, dass isomorphic-fetch mit HttpLink in TypeScript ab sofort gut funktioniert:

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

const link = new HttpLink({
  fetch
})

Alle 49 Kommentare

Was passiert, wenn Sie createHttpLink anstelle von new HttpLink ?

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

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

@dejayc Es gibt den gleichen Fehler, wenn createHttpLink verwendet wird.

Eigentlich habe ich das Problem erkannt. Der Node-Fetch 2.x ist nicht mit _apollo-link_ kompatibel. Die Signatur von _fetch_ ist anders.

Der node-fetch 2.x ist nicht mit apollo-link kompatibel. Die Signatur von fetch ist anders.

Ah, ich schätze, du kannst dich ducken.

Ich bin heute in meiner isomorphen App auf dieses Problem gestoßen. Ich bin nicht ganz damit einverstanden, dass globaler Abruf der Standardfallback ist, insbesondere in diesen Tagen von SSR, aber zumindest war der Fehler etwas informativ:

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

Meine Lösung bestand darin, je nach Knoten-/Browserumgebung entweder node-fetch oder whatwg-fetch bedingt zu verwenden. Oder verwenden Sie einfach cross-fetch was im Grunde dasselbe tut.

So...

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

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

@jmca Die Art und Weise, die Sie für TypeScript vorgeschlagen haben, hat bei mir funktioniert! Vielen Dank!!

Ich bin heute auf dieses Problem gestoßen und habe festgestellt, dass wir nicht mit node-fetch v2 kompatibel sind. Ich glaube, wir sollten dies beheben.

Ich fange jetzt an, cross-fetch aber es importiert nur ein fetch: any ...

(Folgeaktion am 7. Mai 2018: cross-fetch jetzt TypeScript-Typdefinitionen)

cross-fetch wurde noch nicht mit TypeScript-Typdefinitionen ausgeliefert (und @DefinitelyTyped auch nicht).

Während ich darauf warte, dass lquixada/cross-fetch#12 zusammengeführt wird, ist cross-fetch eine Alternative, aber ich habe festgestellt, dass isomorphic-fetch mit HttpLink in TypeScript ab sofort gut funktioniert:

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

const link = new HttpLink({
  fetch
})

Die npmjs.com-Dokumentation ermutigt Benutzer, node-fetch zu verwenden, gibt jedoch nicht an, welche Version. Wie können wir diese Dokumentation aktualisieren?

Hinweis: Die Verwendung von whatwg-fetch ist eine praktikable Problemumgehung.

Gab es diesbezüglich Bewegung?

Die Verwendung von cross-fetch scheint eine seltsame Problemumgehung zu sein, da sie nur node-fetch . Ist das eigentlich kein Problem?

whatwg-fetch ist kein Workaround für diejenigen von uns auf der Serverseite.

Wenn jemand eine PR öffnet, die die richtigen Typdefinitionen enthält, die mit allen fetch-Implementierungen funktionieren, aber eine Typprüfung unterhält, bitte @stubailo mich und ich werde versuchen, zusammenzuführen!

@stubailo Auf Apollo Server verwenden wir dies als Teil von apollo-server-env .

Die Verwendung von HttpLink ist optional, das funktioniert bei mir:

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

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

Gibt es darüber irgendwelche Neuigkeiten ? node-fetch verursacht immer noch Probleme mit apollo-link und TS.

Irgendwelche Neuigkeiten? Immer noch Probleme mit node-fetch

Eine Problemumgehung hierfür besteht darin, @types/node-fetch nicht zu installieren und manuell als GlobalFetch selbst zu definieren.

Fügen Sie dazu Folgendes zu einer beliebigen .d.ts Datei in Ihrem Projekt hinzu;

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

Du kannst einfach ein Zwang-Ding vom Typ as verwenden...

Sicher, aber was bringt es überhaupt, die Typen zu installieren, wenn Sie sie einfach so oder so auf etwas anderes werfen wollen?
Könnte in diesem Fall auch meine Lösung verwenden.

Entschuldigung, ich habe falsch gelesen, was Sie getan haben, ignorieren Sie meinen vorherigen Kommentar.

Dies erfordert jedoch, dass Sie Ihre tsconfig so ändern, dass sie auf den Browser abzielt, da GlobalFetch nur bereitgestellt wird, wenn Sie „dom“ als Eintrag im Feld „lib“ haben: https://github.com/apollographql/apollo-link/issues/ 273#issuecomment -347878009

Zweitens, anstatt .d.ts manuell zu ändern, könnten Sie nicht einfach GlobalFetch['fetch'] an den HTTPLink-Konstruktor übergeben? Das macht es viel weniger versteckt.

  1. Sicher, aber um der Eingabe von müssen Sie GlobalFetch['fetch'] also sehe ich keinen Weg, diese Anforderung zu umgehen .

  2. Ich folge nicht. GlobalFetch['fetch'] ist ein Typ, keine Variable.
    Meinst du das Importieren von node-fetch und das anschließende Umwandeln in GlobalFetch['fetch'] ?
    Das ist für mich keine Option, da ich noImplictAny in meinen Projekten aktiviert habe, sodass ich nichts importieren kann, das keine Definition hat.

Es ist nur ein Workaround, der für mich funktioniert 🤷‍♀️, aber ich merke, es ist alles andere als perfekt (Stichwort: _workaround_).

Ich denke, eine gute Lösung wäre, einfach die Typisierung in eine Vereinigung von GlobalFetch['fetch'] und den Standardtyp des Exports von Node-Fetch zu ändern.
Oder ändern Sie einfach die empfohlene Bibliothek in eine Knotenabrufbibliothek, die GlobalFetch['fetch'] (whatwg-fetch oder was auch immer) entspricht.

  1. Ah, ich wusste nicht, dass das erforderlich ist. BIS.

  2. Tut mir leid, ich habe gerade einen wirklich freien Tag. Sie haben Recht, das ist ein Typ, keine Variable.

https://www.npmjs.com/package/whatwg-fetch sagt ziemlich explizit: „Dieses Projekt funktioniert nicht in Node.js-Umgebungen. Es ist nur für Webbrowser gedacht. Sie sollten sicherstellen, dass Ihre Anwendung dies nicht versucht Paket und führen Sie dieses auf dem Server aus."

Ja, jemand sollte den Fehler wirklich richtig beheben, indem er die Typen korrigiert.

Bei weiterer Überprüfung scheint dies hauptsächlich ein Problem mit node-fetch , also habe ich das obige Problem geöffnet. Es ist jedoch durchaus möglich, dass sie uns sagen, dass wir einfach unseren Typ ändern sollen.

Okay, node-fetch scheint uns zu sagen, dass wir einfach unsere Typen ändern sollen. Ein Hack wäre, die Typen von node-fetch zu importieren und als Workaround hinzuzufügen?

@grantwwu Entschuldigung, die Dinge im Überblick zum GraphQL Summit sind ziemlich hektisch, aber wir haben vor kurzem damit begonnen, ein apollo-env Paket zu verwenden, das node-fetch mit den richtigen Typen reexportiert :

(Wir werden jedoch wahrscheinlich die globalen Abrufexporte aussondern wollen)

Ich habe gerade ein import { fetch } from 'apollo-env' und erhalte _immer noch_ TypeScript-Fehler, wenn ich es an den HttpLink Konstruktor übergebe.

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

Ich habe es in meinem Test geschafft, dies zum Laufen zu bringen:

import { fetch } from 'apollo-env'

......

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

Bei mir funktioniert es immer noch nicht :/

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 welche Versionen von apollo-http-link und apollo-env hast du verwendet? Dies ist auch mit Knoten, oder?

Ja, hier das gleiche. Die Verwendung von apollo-env löst das Problem für mich nicht.

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 : Ich benutze
"apollo-client": "^2.4.12",
"apollo-env": "^0.3.2",
"apollo-link-http": "^1.5.9",

Ich verwende Garn für das Abhängigkeitsmanagement in meiner App

Ich habe für mein Projekt auf

@jacobtani Wie sieht deine tsconfig aus?

apollo-env sich immer noch von dem, was HttpLink erwartet. der Eingabeparameter sollte nicht erforderlich sein

Am Ende habe ich es so überschrieben und es hat funktioniert

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

Ich verwende dies vom Knoten mit diesem

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

BITTE DAS DOCS APOLLO-TEAM PATCHEN! Diese Ausgabe ist über ein Jahr alt

@rlancer Ich apollo-env einen Patch benötigt. Dies ist nicht in diesem Repository, sondern im apollo-tooling Repository.

@JoviDeCroock Es gibt Lösungen, die funktionieren, in den Dokumenten sollte angegeben werden, dass sie verwendet werden sollen, im Gegensatz zu einer, die fehlschlägt und die Leute dazu zwingt, Google für Workarounds zu verwenden.

@JoviDeCroock sowohl apollo-env als auch apollo-tooling hat dieselbe Deklaration der Abruftypen und beide unterscheiden sich von Global['fetch'], die der HttpLink erwartet. Aber das scheint nicht das Problem zu sein, wenn ich das Modul selbst mit der gleichen Deklaration wie apollo-env deklariere, beschwert es sich nicht über Typen. Vielleicht funktioniert der Export nicht

Nun, ich persönlich benutze diese nie. Wenn Sie mich auf eine Lösung hinweisen können, würde ich gerne pr

Ich denke, wenn Sie diese beiden Typen gleich machen, sollte es funktionieren.

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

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

@jmca Danke, Mann, du hast mir den Tag gerettet, habe

@tafelito Danke für deine Lösung, es war sehr hilfreich, aber ich denke, der eigentliche Fehler wurde gefunden und liegt am neuen TypeScript-Update. In der Version 3.6 wurde GlobalFetch entfernt und stattdessen WindowOrWorkerGlobalScope verwendet. Dies zwingt uns also, die Version in unseren Abhängigkeiten von package.json "typescript": "3.5.1" .

Hier ist der Link

Um den obigen Kommentar zu wiederholen, muss mein Repo beim Typoskript v3.5.3 bleiben

Ich denke, wenn Sie diese beiden Typen gleich machen, sollte es funktionieren.

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

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

Ich konnte es nur mit dem zweiten Teil beheben, danke @tafelito

gleicher Fehler.

"@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 });

Ich habe das gleiche Problem in meiner Bewerbung. Ich löse das Casting zu any so:

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

Letztendlich besteht das Problem darin, dass die node-fetch & zugehörigen Eingaben absichtlich von der Spezifikation abweichen:

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

Compilerfehler sind daher unvermeidlich, wenn Sie keine neuen Typisierungen erstellen oder diese nicht hinzufügen.

Ich habe mich entschieden, node-fetch :

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

es ist nicht großartig, aber node-fetch != fetch, was ... grummelt ... ist irreführend. node-fetch-like vielleicht passender gewesen, und die Erweiterungen _out_ in der Basis-Node-Fetch-Implementierung zu belassen, um die Node-Fetch-Konformität zu gewährleisten, hätte uns einen Gefallen getan :)

Dies mag völlig irrelevant sein ... aber ... hatte am letzten Tag oder so das gleiche Problem ... nur um zu erkennen, dass 'fetch' im Browser verfügbar ist, aber nicht auf der Serverseite. Wenn Ihre Anwendung das Abrufen vom Browser durchführt, ist es sinnlos, die Verbindung auf der Serverseite vorab zu rendern.

In meinem Fall habe ich mit NextJS die Komponente geändert, für die der http-Link nicht serverseitig gerendert werden musste, gemäß https://nextjs.org/docs#with -no-ssr

Ich hatte das gleiche Problem, anstatt node-fetch und @types/node-fetch installieren, ging ich direkt zu apollo-env und bam! alle Fehler weg!

Ich habe es geschafft, dies mit isomorphic-fetch . zum Laufen zu bringen

package.json (alle Versionen ausgewählt für Kompatibilität mit der von appsync verwendeten)
    "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
            })
          ])
        })
      });

Betrachten Sie cross-fetch !

Dies funktioniert mit Typoskript und Knoten (nicht Browser).

import fetch from 'cross-fetch'

const httpLink = new HttpLink({
  uri: "<your-uri>",
  fetch,
})
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen