Apollo-link: Использование node-fetch с apollo-link-http

Созданный на 21 февр. 2018  ·  49Комментарии  ·  Источник: apollographql/apollo-link


Использование HttpLink с node-fetch дает следующую ошибку

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

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

Предполагаемый результат:
Согласно документации, это должно было быть скомпилировано.

Фактический результат:

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

Как воспроизвести проблему:
Следующие версии используются для написания вышеуказанного кода.

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


Используйте указанные выше версии и создайте экземпляр HttpLink в машинописном тексте, чтобы увидеть указанную выше ошибку.

Самый полезный комментарий

(Продолжение от 7 мая 2018 г .: cross-fetch теперь поставляется с определениями типов TypeScript)

cross-fetch еще не поставляется с определениями типов TypeScript (как и @DefinitiTyped).

Ожидая объединения lquixada / cross-fetch # 12, cross-fetch - альтернатива, я обнаружил, что isomorphic-fetch работает нормально с HttpLink в TypeScript на данный момент:

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

const link = new HttpLink({
  fetch
})

Все 49 Комментарий

Что произойдет, если вы используете createHttpLink вместо new HttpLink ?

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

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

@dejayc При использовании createHttpLink возникает такая же ошибка.

Собственно, с проблемой разобрался. Node-fetch 2.x несовместим с _apollo-link_. Подпись _fetch_ другая.

Node-fetch 2.x несовместим с apollo-link. Подпись выборки другая.

Ах, я думаю, ты можешь уклониться от удара.

Сегодня я столкнулся с этой проблемой в своем изоморфном приложении. Я не совсем согласен с тем, что глобальная выборка является резервным вариантом по умолчанию, особенно в наши дни SSR, но, по крайней мере, ошибка была несколько информативной:

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

Мое решение заключалось в том, чтобы условно использовать node-fetch или whatwg-fetch зависимости от среды узла / браузера. Или просто используйте cross-fetch который в основном делает то же самое.

Так...

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

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

@jmca То, как вы предложили TypeScript, у меня сработало! Спасибо!!

Сегодня я столкнулся с этой проблемой и обнаружил, что мы несовместимы с node-fetch v2, я считаю, что мы должны это исправить.

Я начинаю использовать cross-fetch сейчас, но он просто импортирует fetch: any ...

(Продолжение от 7 мая 2018 г .: cross-fetch теперь поставляется с определениями типов TypeScript)

cross-fetch еще не поставляется с определениями типов TypeScript (как и @DefinitiTyped).

Ожидая объединения lquixada / cross-fetch # 12, cross-fetch - альтернатива, я обнаружил, что isomorphic-fetch работает нормально с HttpLink в TypeScript на данный момент:

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

const link = new HttpLink({
  fetch
})

Документация npmjs.com поощряет пользователей использовать node-fetch, но не указывает, какая версия. Как мы можем обновить эту документацию?

Примечание: использование whatwg-fetch - жизнеспособный обходной путь.

Есть ли какие-нибудь движения по этому поводу?

Использование cross-fetch кажется странным обходным путем, поскольку оно просто использует node-fetch . Разве это не проблема?

whatwg-fetch не является обходным решением для тех из нас, кто работает на стороне сервера.

Если кто-то откроет PR, который включает правильные определения типов, которые будут работать со всеми реализациями выборки, но поддерживают некоторую проверку типов, пожалуйста, @stubailo меня, и я попытаюсь объединиться!

@stubailo На сервере Apollo мы используем это как часть apollo-server-env .

использование HttpLink не является обязательным, это работает для меня:

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

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

Есть новости по этому поводу? node-fetch по-прежнему вызывает проблемы с apollo-link и TS.

Любые новости? По-прежнему возникают проблемы с node-fetch

Чтобы решить эту проблему, не следует устанавливать @types/node-fetch и вручную определять его как GlobalFetch.

Для этого добавьте следующее в любой файл .d.ts в вашем проекте;

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

Вы можете просто использовать принуждение типа as ...

Конечно, но какой смысл вообще устанавливать типы, если вы все равно собираетесь принудительно применить его к чему-то другому?
В этом случае можно также использовать мое решение.

Извините, я неправильно понял, что вы делали, проигнорируйте мой предыдущий комментарий.

Однако для этого необходимо изменить tsconfig, чтобы настроить таргетинг на браузер, поскольку GlobalFetch предоставляется только в том случае, если у вас есть «dom» в качестве записи в поле «lib»: https://github.com/apollographql/apollo-link/issues/ 273 # issuecomment -347878009

Во-вторых, вместо того, чтобы вручную изменять .d.ts , не могли бы вы просто передать GlobalFetch['fetch'] в конструктор HTTPLink? Это делает его менее скрытым.

  1. Конечно, но чтобы соответствовать типу HttpLink, вы должны использовать GlobalFetch['fetch'] любом случае, поэтому я не вижу способа обойти это требование.

  2. Я не слежу. GlobalFetch['fetch'] - это тип, а не переменная.
    Вы имеете в виду импорт node-fetch, а затем преобразование его в GlobalFetch['fetch'] ?
    Для меня это не вариант, поскольку в моих проектах включен noImplictAny поэтому я не могу импортировать ничего, что не имеет определения.

Это просто обходной путь, который у меня работает 🤷‍♀️, но я понимаю, что он далек от совершенства (ключевое слово: _workaround_).

Я думаю, что хорошим решением было бы просто изменить типирование на объединение GlobalFetch['fetch'] и тип экспорта по умолчанию для выборки узлов.
Или просто измените рекомендованную библиотеку на библиотеку для выборки узлов, которая ДЕЙСТВИТЕЛЬНО соответствует GlobalFetch['fetch'] (whatwg-fetch или что-то еще).

  1. Ах, я не понимал, что это было необходимо. TIL.

  2. Извини, у меня действительно выходной. Вы правы, это тип, а не переменная.

https://www.npmjs.com/package/whatwg-fetch довольно четко заявляет, что «Этот проект не работает в средах Node.js. Он предназначен только для веб-браузеров. Вы должны убедиться, что ваше приложение не пытается package и запустите его на сервере ".

Да, кто-то действительно должен исправить ошибку, исправив типы.

При дальнейшем рассмотрении выяснилось, что это в основном проблема с node-fetch , поэтому я открыл вышеупомянутую проблему. Однако вполне возможно, что они скажут нам просто изменить наши типы.

Хорошо, кажется, node-fetch говорит нам просто изменить наши типы. Один из способов взлома - импортировать типы node-fetch и добавить это в качестве обходного пути?

@grantwwu Извините, с описанием GraphQL Summit все довольно беспокойно, но недавно мы начали использовать пакет apollo-env , который реэкспортирует node-fetch с правильными типами: https: // github .com / apollographql / apollo-инструменты / дерево / мастер / пакеты / apollo-env

(Мы, вероятно, захотим отделить глобальный экспорт выборки)

Я только что выполнил import { fetch } from 'apollo-env' и все еще _ получаю ошибки TypeScript при передаче его в конструктор 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]'.

Мне удалось заставить это работать в моем тесте:

import { fetch } from 'apollo-env'

......

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

У меня все еще не работает: /

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, какие версии apollo-http-link и apollo-env вы использовали? Кроме того, это с узлом, верно?

Да, здесь то же самое. Использование apollo-env для меня не решает проблему.

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 : я использую
"apollo-client": "^ 2.4.12",
"apollo-env": "^ 0.3.2",
"apollo-link-http": "^ 1.5.9",

Я использую пряжу для управления зависимостями в своем приложении

Я перешел на graphql-запрос для своего проекта.

@jacobtani Как выглядит ваш tsconfig?

apollo-env по-прежнему отличается от того, что ожидает HttpLink. входной параметр не требуется

Я закончил тем, что переопределил это, и это сработало

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

Я использую это из узла, используя это

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

ПОЖАЛУЙСТА, ЗАПИШИТЕ КОМАНДУ DOCS APOLLO! Этому выпуску больше года

@rlancer Я предполагаю, что это так, потому что, как упоминалось выше в вашем комментарии, он еще не исправлен, поскольку apollo-env нуждается в патче. Этого нет в этом репо, а в репозитории apollo-tooling .

@JoviDeCroock Существуют решения, которые работают, в документах должно быть указано, что их следует использовать, в отличие от того, которое дает сбой и заставляет людей искать обходные пути в Google.

@JoviDeCroock и apollo-env и apollo-tooling имеют одинаковое объявление типов выборки, и оба они отличаются от Global ['fetch'], ожидаемого HttpLink. Но это не похоже на проблему, если я сам объявляю модуль с тем же объявлением, что и apollo-env он не жалуется на типы. Может экспорт не работает

Что ж, лично я этим никогда не пользуюсь. Если вы можете указать мне решение, я с удовольствием

Я думаю, что если сделать эти два типа одинаковыми, это должно сработать.

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

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

@jmca Спасибо, чувак, ты спас мне день, получил удар головой получил проблему Я не определен в новом createUploadLink при использовании шутливого тестирования.

@tafelito Спасибо за ваше решение, оно было очень полезно, но я думаю, что настоящая ошибка была обнаружена, и это связано с новым обновлением TypeScript. В версии 3.6 GlobalFetch удаляется и вместо него используется WindowOrWorkerGlobalScope , поэтому это заставляет нас закрыть версию в наших зависимостях package.json "typescript": "3.5.1" .

Вот ссылка

Чтобы повторить приведенный выше комментарий, мое репо должно придерживаться машинописного текста v3.5.3

Я думаю, что если сделать эти два типа одинаковыми, это должно сработать.

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

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

Мне удалось исправить это, используя только вторую часть, спасибо @tafelito

та же проблема.

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

У меня такая же проблема в моем приложении. Я решаю приведение к any вот так:

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

в конечном итоге проблема в том, что node-fetch & связанные типы намеренно отклоняются от спецификации:

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

поэтому ошибки компилятора неизбежны, если вы не уменьшите или не создадите новые типы, которые опускают эти дополнения.

я выбрал понижающее значение node-fetch :

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

это не здорово, но node-fetch! = fetch, который ... ворчит ... вводит в заблуждение. node-fetch-like возможно, был бы более подходящим, и оставление расширений _out_ в базовой реализации node-fetch для обеспечения соответствия node-fetch сделало бы одолжение таким, как мы :)

Это могло быть совершенно неуместно ... но ... была такая же проблема в последний день или около того ... только для того, чтобы понять, что "выборка" - это то, что доступно в браузере, но не на стороне сервера. Если ваше приложение будет выполнять выборку из браузера, бессмысленно предварительно визуализировать соединение на стороне сервера.

В моем случае, используя NextJS, я изменил компонент, которому необходимо, чтобы http-ссылка не отображалась на стороне сервера согласно https://nextjs.org/docs#with -no-ssr

У меня была та же проблема, вместо установки node-fetch и @types/node-fetch я сразу пошел с apollo-env и бац! все ошибки ушли!

Мне удалось заставить это работать с изоморфной выборкой

package.json (все версии выбраны для совместимости с версией, используемой 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" ],
...
код
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
            })
          ])
        })
      });

Рассмотрим cross-fetch !

Это работает с машинописным текстом и узлом (не с браузером).

import fetch from 'cross-fetch'

const httpLink = new HttpLink({
  uri: "<your-uri>",
  fetch,
})
Была ли эта страница полезной?
0 / 5 - 0 рейтинги