Apollo-link: Usando node-fetch con apollo-link-http

Creado en 21 feb. 2018  ·  49Comentarios  ·  Fuente: apollographql/apollo-link


El uso de HttpLink con node-fetch da el siguiente error

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

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

Resultado esperado:
De acuerdo con la documentación, lo anterior debería haberse compilado.

Resultado real:

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

Cómo reproducir el problema:
Las siguientes versiones se utilizan para escribir el código anterior.

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


Utilice las versiones anteriores y cree la instancia de HttpLink en mecanografiado para ver el error anterior.

Comentario más útil

(Seguimiento el 7 de mayo de 2018: cross-fetch ahora viene con definiciones de tipo TypeScript)

cross-fetch aún no se ha enviado con definiciones de tipo TypeScript (ni @DefinitelyTyped).

Mientras esperaba que lquixada / cross-fetch # 12 se fusionara cross-fetch es una alternativa, encontré que isomorphic-fetch funciona bien con HttpLink en TypeScript a partir de ahora:

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

const link = new HttpLink({
  fetch
})

Todos 49 comentarios

¿Qué sucede si usa createHttpLink lugar de new HttpLink ?

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

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

@dejayc Da el mismo error cuando se usa createHttpLink.

De hecho, descubrí el problema. Nodo-fetch 2.x no es compatible con _apollo-link_. La firma de _fetch_ es diferente.

Nodo-fetch 2.x no es compatible con apollo-link. La firma de recuperación es diferente.

Ah, supongo que puedes agacharte para darle un puñetazo.

Encontré este problema hoy en mi aplicación isomórfica. No estoy totalmente de acuerdo con que la recuperación global sea la alternativa predeterminada, especialmente en estos días de SSR, pero al menos el error fue algo informativo:

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

Mi solución fue usar condicionalmente node-fetch o whatwg-fetch dependiendo del entorno del nodo / navegador. O simplemente use cross-fetch que básicamente hace lo mismo.

Entonces...

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

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

@jmca ¡ La forma en que sugirió para TypeScript funcionó para mí! ¡¡Gracias!!

Hoy me encontré con este problema y descubrí que no somos compatibles con node-fetch v2, creo que deberíamos solucionarlo.

Empiezo a usar cross-fetch ahora, pero solo importa un fetch: any ...

(Seguimiento el 7 de mayo de 2018: cross-fetch ahora viene con definiciones de tipo TypeScript)

cross-fetch aún no se ha enviado con definiciones de tipo TypeScript (ni @DefinitelyTyped).

Mientras esperaba que lquixada / cross-fetch # 12 se fusionara cross-fetch es una alternativa, encontré que isomorphic-fetch funciona bien con HttpLink en TypeScript a partir de ahora:

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

const link = new HttpLink({
  fetch
})

La documentación de npmjs.com anima a los usuarios a utilizar node-fetch, pero no especifica qué versión. ¿Cómo podemos actualizar esa documentación?

Nota: usar whatwg-fetch es una solución alternativa viable.

¿Ha habido algún movimiento al respecto?

Usar cross-fetch parece una solución extraña ya que solo usa node-fetch . ¿No es eso realmente un problema?

whatwg-fetch no es una solución para aquellos de nosotros en el lado del servidor.

Si alguien abre un PR que incluye las definiciones de tipo correctas que funcionarán con todas las implementaciones de recuperación, pero mantiene alguna verificación de tipo, ¡por favor @stubailo y trataré de fusionar!

@stubailo En Apollo Server usamos esto como parte de apollo-server-env .

usar HttpLink es opcional, esto funciona para mí:

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

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

Alguna noticia sobre esto ? node-fetch todavía causa problemas con apollo-link y TS.

¿Hay noticias? Sigo teniendo problemas con node-fetch

Una solución para esto es no instalar @types/node-fetch y definirlo manualmente como GlobalFetch usted mismo.

Para hacer esto, agregue lo siguiente a cualquier archivo .d.ts en su proyecto;

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

Puede usar una cosa de coerción de tipo as ...

Claro, pero ¿cuál es el punto de instalar los tipos, si de todas formas vas a forzar el lanzamiento a otra cosa?
Bien podría usar mi solución en ese caso.

Lo siento, leí mal lo que estabas haciendo, ignora mi comentario anterior.

Sin embargo, esto requiere que modifique su tsconfig para apuntar al navegador, ya que GlobalFetch solo se proporciona si tiene "dom" como entrada en el campo "lib": https://github.com/apollographql/apollo-link/issues/ 273 # issuecomment -347878009

En segundo lugar, en lugar de modificar manualmente un .d.ts , ¿no podría simplemente pasar GlobalFetch['fetch'] al constructor HTTPLink? Eso lo hace mucho menos oculto.

  1. Claro, pero para cumplir con la escritura de HttpLink, debe usar GlobalFetch['fetch'] independientemente, así que no veo ninguna forma de evitar ese requisito.

  2. Yo no sigo. GlobalFetch['fetch'] es un tipo, no una variable.
    ¿Te refieres a importar node-fetch y luego convertirlo en GlobalFetch['fetch'] ?
    Esa no es una opción para mí, ya que tengo noImplictAny habilitado en mis proyectos, por lo que no puedo importar nada que no tenga una definición.

Es solo una solución que me funciona 🤷‍♀️, pero me doy cuenta de que está lejos de ser perfecta (palabra clave: _workaround_).

Creo que una buena solución sería simplemente cambiar la escritura a una unión de GlobalFetch['fetch'] y el tipo predeterminado de exportación de búsqueda de nodo.
O simplemente cambie la biblioteca recomendada a una biblioteca de búsqueda de nodo que SÍ se ajuste a GlobalFetch['fetch'] (whatwg-fetch o lo que sea).

  1. Ah, no me di cuenta de que era necesario. TIL.

  2. Lo siento, estoy teniendo un día realmente malo. Tienes razón, ese es un tipo, no una variable.

https://www.npmjs.com/package/whatwg-fetch afirma de manera bastante explícita que "Este proyecto no funciona en entornos Node.js. Está destinado únicamente a navegadores web. Debe asegurarse de que su aplicación no intente package y ejecútelo en el servidor ".

Sí, alguien debería corregir el error correctamente corrigiendo los tipos.

Tras una revisión adicional, esto parece ser principalmente un problema con node-fetch , por lo que abrí el problema anterior. Sin embargo, es muy posible que nos digan que simplemente cambiemos nuestros tipos.

De acuerdo, node-fetch parece estar diciéndonos que cambiemos nuestros tipos. Un truco sería importar los tipos de node-fetch y agregar eso como una solución alternativa.

@grantwwu Lo sentimos, las cosas están bastante agitadas en el resumen de GraphQL Summit, pero recientemente comenzamos a usar un paquete apollo-env que reexporta node-fetch con los tipos correctos: https: // github .com / apollographql / apollo-tooling / tree / master / packages / apollo-env

(Sin embargo, probablemente querremos separar las exportaciones de recuperación global)

Acabo de hacer un import { fetch } from 'apollo-env' y _todavía_ obteniendo errores de TypeScript al pasarlo al constructor 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]'.

Me las arreglé para que esto funcione en mi prueba:

import { fetch } from 'apollo-env'

......

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

Todavía no me funciona: /

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, ¿ qué versiones de apollo-http-link y apollo-env

Sí, lo mismo aquí. Usar apollo-env no me resuelve el problema.

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

Utilizo hilo para la gestión de dependencias en mi aplicación

@jacobtani ¿Cómo es tu tsconfig?

apollo-env sigue siendo diferente de lo que espera HttpLink. el parámetro de entrada no debería ser necesario

Terminé anulándolo así y funcionó

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

Estoy usando esto desde el nodo usando esto

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

¡POR FAVOR PARCHE EL EQUIPO DOCS APOLLO! Este problema tiene más de un año

@rlancer Supongo que este es el caso porque, como se mencionó anteriormente en su comentario, aún no se ha solucionado ya que apollo-env necesita un parche. Esto no está en este repositorio sino en el repositorio apollo-tooling .

@JoviDeCroock Hay soluciones que funcionan, los documentos deben indicar que se utilicen en lugar de una que falla y obliga a la gente a buscar soluciones en Google.

@JoviDeCroock tanto apollo-env como apollo-tooling tienen la misma declaración de tipos de recuperación y ambos son diferentes del ['fetch'] global que espera HttpLink. Pero este no parece ser el problema, si declaro el módulo yo mismo con la misma declaración que apollo-env , no se queja de los tipos. Quizás la exportación no esté funcionando

Bueno, yo personalmente nunca los uso. Si puede indicarme una solución, con mucho gusto lo haría.

Supongo que al hacer estos 2 tipos iguales debería funcionar.

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

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

@jmca Gracias, hombre, me salvó el día, me

@tafelito Gracias por tu solución, fue muy útil, pero creo que se encontró el error real y se debe a la nueva actualización de TypeScript. En su versión 3.6, GlobalFetch se retira y WindowOrWorkerGlobalScope se utiliza en su lugar, por lo que esto nos obliga a cerrar la versión en nuestras dependencias de la package.json "typescript": "3.5.1" .

Aqui esta el enlace

Para hacer eco del comentario anterior, mi repositorio tiene que seguir con el mecanografiado v3.5.3

Supongo que al hacer estos 2 tipos iguales debería funcionar.

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

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

Lo he podido arreglar usando solo la segunda parte, gracias @tafelito

mismo problema.

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

Tengo el mismo problema en mi aplicación. Resuelvo la transmisión a any así:

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 última instancia, el problema es que node-fetch y las mecanografías asociadas se desvían intencionalmente de la especificación:

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

por lo que los errores del compilador son inevitables si no abatimos o crea nuevos tipos que omiten estas adiciones.

Elegí abatir node-fetch :

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

no es genial, pero node-fetch! = fetch, que ... refunfuña ... es engañoso. node-fetch-like puede haber sido más apropiado, y dejar las extensiones _out_ en la implementación base de búsqueda de nodo para mantener la conformidad de búsqueda de nodo nos hubiera hecho un favor :)

Esto puede ser completamente irrelevante ... pero ... tuvo el mismo problema durante el último día más o menos ... solo para darse cuenta de que 'buscar' es algo que está disponible en el navegador, pero no en el lado del servidor. Si su aplicación va a buscar desde el navegador, no tiene sentido pre-renderizar la conexión en el lado del servidor.

En mi caso, al usar NextJS, cambié el componente que necesitaba que el enlace http no se mostrara en el lado del servidor según https://nextjs.org/docs#with -no-ssr

Estaba teniendo el mismo problema, en lugar de instalar node-fetch y @types/node-fetch , fui directamente con apollo-env y ¡bam! ¡Todos los errores desaparecieron!

Me las arreglé para que esto funcione con isomorphic-fetch

package.json (todas las versiones seleccionadas por compatibilidad con la utilizada por 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",
... / tipings / 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" ],
...
código
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
            })
          ])
        })
      });

¡Considere cross-fetch !

Esto funciona con mecanografiado y nodo (no navegador).

import fetch from 'cross-fetch'

const httpLink = new HttpLink({
  uri: "<your-uri>",
  fetch,
})
¿Fue útil esta página
0 / 5 - 0 calificaciones