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

Criado em 21 fev. 2018  ·  49Comentários  ·  Fonte: apollographql/apollo-link


Usar HttpLink com node-fetch dá o seguinte erro

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

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

Resultado pretendido:
De acordo com a documentação, o acima deve ter sido 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);

Como reproduzir o problema:
As versões a seguir são usadas para escrever o código acima.

    "@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 as versões acima e crie a instância de HttpLink no texto digitado para ver o erro acima.

Comentários muito úteis

(Acompanhamento em 7 de maio de 2018: cross-fetch agora vem com definições de tipo TypeScript)

cross-fetch ainda não foi enviado com definições de tipo TypeScript (nem @DefinitelyTyped).

Enquanto esperava que lquixada / cross-fetch # 12 fosse mesclado cross-fetch é uma alternativa, descobri que isomorphic-fetch funcionando bem com HttpLink no TypeScript a partir de agora:

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

const link = new HttpLink({
  fetch
})

Todos 49 comentários

O que acontece se você usar createHttpLink vez de new HttpLink ?

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

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

@dejayc Dá o mesmo erro quando createHttpLink é usado.

Na verdade, descobri o problema. O node-fetch 2.x não é compatível com _apollo-link_. A assinatura de _fetch_ é diferente.

O node-fetch 2.x não é compatível com apollo-link. A assinatura de busca é diferente.

Ah, acho que você pode se esquivar e dar um soco nele.

Eu me deparei com esse problema hoje em meu aplicativo isomórfico. Não concordo totalmente com a busca global sendo o substituto padrão, especialmente nos dias de SSR, mas pelo menos o erro foi um tanto 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';

Minha solução foi usar condicionalmente node-fetch ou whatwg-fetch dependendo do ambiente do nó / navegador. Ou apenas use cross-fetch que basicamente faz a mesma coisa.

Então...

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

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

@jmca A maneira que você sugeriu para o TypeScript funcionou para mim! Obrigado!!

Encontrei esse problema hoje e descobri que não somos compatíveis com node-fetch v2, acredito que devemos consertar isso.

Eu começo a usar cross-fetch agora, mas apenas importa um fetch: any ...

(Acompanhamento em 7 de maio de 2018: cross-fetch agora vem com definições de tipo TypeScript)

cross-fetch ainda não foi enviado com definições de tipo TypeScript (nem @DefinitelyTyped).

Enquanto esperava que lquixada / cross-fetch # 12 fosse mesclado cross-fetch é uma alternativa, descobri que isomorphic-fetch funcionando bem com HttpLink no TypeScript a partir de agora:

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

const link = new HttpLink({
  fetch
})

A documentação do npmjs.com incentiva os usuários a usar o node-fetch, mas não especifica qual versão. Como podemos atualizar essa documentação?

Nota: usar whatwg-fetch é uma solução alternativa viável.

Houve algum movimento sobre isso?

Usar cross-fetch parece uma alternativa estranha, pois usa apenas node-fetch . Isso não é realmente um problema?

whatwg-fetch não é uma solução alternativa para nós do lado do servidor.

Se alguém abrir um PR que inclui as definições de tipo corretas que funcionará com todas as implementações de busca, mas mantém alguma verificação de tipo, por favor, @stubailo me e tentarei mesclar!

@stubailo No Apollo Server, usamos isso como parte de apollo-server-env .

usar HttpLink é opcional, isso funciona para mim:

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

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

Alguma novidade sobre isso ? node-fetch ainda causa problemas com apollo-link e TS.

Qualquer notícia? Ainda tendo problemas com node-fetch

Uma solução alternativa para isso é não instalar @types/node-fetch e defini-lo manualmente como GlobalFetch você mesmo.

Para fazer isso, adicione o seguinte a qualquer arquivo .d.ts em seu projeto;

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

Você pode apenas usar uma coisa de coerção de tipo as ...

Claro, mas de que adianta instalar os tipos, se você apenas forçará a conversão para outra coisa?
Poderia muito bem usar minha solução nesse caso.

Desculpe, eu li errado o que você estava fazendo, ignore meu comentário anterior.

No entanto, isso requer que você modifique seu tsconfig para direcionar o navegador, já que GlobalFetch só é fornecido se você tiver "dom" como uma entrada no campo "lib": https://github.com/apollographql/apollo-link/issues/ 273 # issuecomment -347878009

Em segundo lugar, em vez de modificar manualmente um .d.ts , você não poderia simplesmente passar GlobalFetch['fetch'] para o construtor HTTPLink? Isso o torna muito menos escondido.

  1. Claro, mas para estar em conformidade com a digitação do HttpLink, você deve usar GlobalFetch['fetch'] independentemente, então não vejo como contornar esse requisito.

  2. Eu não sigo. GlobalFetch['fetch'] é um tipo, não uma variável.
    Você quer dizer importar node-fetch e então lançá-lo em GlobalFetch['fetch'] ?
    Isso não é uma opção para mim, pois tenho noImplictAny habilitado em meus projetos, então não posso importar nada que não tenha uma definição.

É apenas uma solução alternativa que funciona para mim 🤷‍♀️, mas percebo que está longe de ser perfeita (palavra-chave: _workaround_).

Eu acho que uma boa solução seria apenas mudar a digitação para uma união de GlobalFetch['fetch'] e o tipo padrão de exportação do node-fetch.
Ou apenas mude a biblioteca recomendada para uma lib de busca de nó que SEJA conforme GlobalFetch['fetch'] (whatwg-fetch ou qualquer outro).

  1. Ah, eu não sabia que era necessário. TIL.

  2. Desculpe, estou tendo um dia realmente ruim. Você está certo, isso é um tipo, não uma variável.

https://www.npmjs.com/package/whatwg-fetch afirma de forma bastante explícita que "Este projeto não funciona em ambientes Node.js. Destina-se apenas a navegadores da web. Você deve garantir que seu aplicativo não tente pacote e execute-o no servidor. "

Sim, alguém realmente deveria consertar o bug corretamente consertando os tipos.

Após uma análise mais aprofundada, este parece ser principalmente um problema com node-fetch , então abri a edição acima. É perfeitamente possível que eles nos digam apenas para mudar nossos tipos, no entanto.

Ok, node-fetch parece estar nos dizendo para apenas mudar nossos tipos. Um hack seria importar os tipos de node-fetch e adicionar isso como uma solução alternativa?

@grantwwu Desculpe, as coisas estão muito agitadas no resumo do GraphQL Summit, mas recentemente começamos a usar um pacote apollo-env que reexporta node-fetch com os tipos certos: https: // github .com / apollographql / apollo-tooling / tree / master / packages / apollo-env

(Provavelmente, desejaremos separar as exportações globais de busca)

Acabei de fazer um import { fetch } from 'apollo-env' e _ainda_ estou recebendo erros do TypeScript ao passá-lo para o construtor 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]'.

Consegui fazer isso funcionar no meu teste:

import { fetch } from 'apollo-env'

......

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

Ainda não está funcionando para mim: /

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 quais versões do apollo-http-link e apollo-env você usou? Além disso, isso é com o nó, certo?

Sim, o mesmo aqui. Usar o apollo-env não resolve o problema para mim.

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

Eu uso o yarn para gerenciamento de dependências em meu aplicativo

Mudei para

@jacobtani Qual é a aparência do seu tsconfig?

apollo-env ainda é diferente do que o HttpLink espera. o parâmetro de entrada não deve ser necessário

Acabei substituindo assim e funcionou

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

Estou usando isso do nó usando isso

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

FAÇA ATENÇÃO À EQUIPE DOCS APOLLO! Este problema tem mais de um ano

@rlancer Presumo que seja esse o caso porque, conforme mencionado acima em seu comentário, ainda não foi corrigido, pois apollo-env precisa de um patch. Isso não está neste repositório, mas no repositório apollo-tooling .

@JoviDeCroock Existem soluções que funcionam, os documentos devem indicar como usá-las ao invés de uma que falha e força as pessoas a procurarem soluções alternativas no Google.

@JoviDeCroock apollo-env e apollo-tooling têm a mesma declaração de tipos de busca e ambos são diferentes do Global ['fetch'] que o HttpLink espera. Mas esse não parece ser o problema, se eu mesmo declaro o módulo com a mesma declaração de apollo-env ele não reclama dos tipos. Talvez a exportação não esteja funcionando

Bem, eu pessoalmente nunca uso isso. Se você puder me apontar uma solução, eu ficaria feliz em

Eu acho que ao fazer esses 2 tipos o mesmo deve funcionar.

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

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

@jmca Obrigado cara, você salvou meu dia,

@tafelito Obrigado pela solução, foi muito útil, mas acho que o verdadeiro erro foi encontrado e é devido à nova atualização do TypeScript. Em sua versão 3.6, GlobalFetch é removido e WindowOrWorkerGlobalScope é usado, então isso nos força a fechar a versão em nossas dependências do package.json "typescript": "3.5.1" .

Aqui está o link

Para ecoar o comentário acima, meu repositório deve ficar com o texto datilografado v3.5.3

Eu acho que ao fazer esses 2 tipos o mesmo deve funcionar.

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

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

Consegui consertar usando apenas a segunda parte, obrigado @tafelito

o mesmo 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 });

Eu tenho o mesmo problema em meu aplicativo. Eu resolvo lançar para any assim:

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

em última análise, o problema é que node-fetch e tipificações associadas desviam-se intencionalmente das especificações:

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

portanto, os erros do compilador são inevitáveis ​​se você não fizer downcast ou criar novas tipificações que omitam essas adições.

eu escolhi reduzir node-fetch :

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

não é ótimo, mas node-fetch! = fetch, que ... resmunga ... é enganoso. node-fetch-like pode ter sido mais apropriado, e deixar as extensões _out_ na implementação do node-fetch de base para manter a conformidade do node-fetch teria feito um favor a nós :)

Isso pode ser completamente irrelevante ... mas ... teve o mesmo problema no último dia ou depois ... apenas para perceber que 'buscar' é algo que está disponível no navegador, mas não no lado do servidor. Se o seu aplicativo vai buscar no navegador, é meio inútil pré-renderizar a conexão no lado do servidor.

No meu caso, usando NextJS, mudei o componente que precisava do link http para não ser renderizado no lado do servidor de acordo com https://nextjs.org/docs#with -no-ssr

Eu estava tendo o mesmo problema, em vez de instalar node-fetch e @types/node-fetch fui direto com apollo-env e bam! todos os erros se foram!

Consegui fazer funcionar com isomorphic-fetch

package.json (todas as versões selecionadas para compatibilidade com a usada pelo 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" ],
...
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 !

Isso funciona com texto datilografado e nó (não com navegador).

import fetch from 'cross-fetch'

const httpLink = new HttpLink({
  uri: "<your-uri>",
  fetch,
})
Esta página foi útil?
0 / 5 - 0 avaliações