ChatGPT解决这个技术问题 Extra ChatGPT

ReferenceError: fetch is not defined

I have this error when I compile my code in node.js, how can I fix it?

RefernceError: fetch is not defined

https://i.stack.imgur.com/3Syvz.png

This is the function I am doing, it is responsible for recovering information from a specific movie database.

function getMovieTitles(substr){  
  pageNumber=1;
  let url = 'https://jsonmock.hackerrank.com/api/movies/search/?Title=' + substr + "&page=" + pageNumber;
  fetch(url).then((resp) => resp.json()).then(function(data) {
    let movies = data.data;
    let totPages = data.total_pages;
    let sortArray = [];
    for(let i=0; i<movies.length;i++){
        sortArray.push(data.data[i].Title);
     }
    for(let i=2; i<=totPages; i++){
           let newPage = i;
           let url1 = 'https://jsonmock.hackerrank.com/api/movies/search/?Title=' + substr + "&page=" + newPage;

          fetch(url1).then(function(response) {
              var contentType = response.headers.get("content-type");
              if(contentType && contentType.indexOf("application/json") !== -1) {
                return response.json().then(function(json) {
                  //console.log(json); //uncomment this console.log to see the JSON data.

                 for(let i=0; i<json.data.length;i++){
                    sortArray.push(json.data[i].Title);
                 }

                 if(i==totPages)console.log(sortArray.sort());

                });
              } else {
                console.log("Oops, we haven't got JSON!");
              }
            });

        }
  })
  .catch(function(error) {
    console.log(error);
  });   
}
Welcome to SO, please provide the details on what have you tried so far? Please provide a Minimal, Complete, and Verifiable example wherever required. Also please take the time to read How to Ask
fetch is not a standard nodejs method - you need node-fetch
fetch() was designed for the browser and then back-ported to node.js in a third party module whcih you are apparently missing. The request() or request-promise() library is more natively built for node.js and supports a much wider range of options for node.js including streams, a zillion authentication methods, etc...

E
Endless

The fetch API is not implemented in Node.

You need to use an external module for that, like node-fetch.

Install it in your Node application like this

npm install node-fetch

then put the line below at the top of the files where you are using the fetch API:

import fetch from "node-fetch";

Following these instructions, I had to save my file with the .mjs extension to make it work.
The Fetch API has been implemented in Node and should be released in a year or so.
E
Endless

This is a quick dirty fix, please try to eliminate this usage in production code.

If fetch has to be accessible with a global scope

import fetch from 'node-fetch'
globalThis.fetch = fetch

This was the only way that I was able to get WebStorm to recognize the promise returned by fetch and autocomplete the available methods. Agreed that it should be avoided in production, but very helpful for local dev!
@FoxMulder900 This is how you could have still IntelliSense without having it global defined: const nodeFetch = require('node-fetch') as typeof fetch;
R
Richard Vergis

You can use cross-fetch from @lquixada

Platform agnostic: browsers, node or react native

Install

npm install --save cross-fetch

Usage

With promises:

import fetch from 'cross-fetch';
// Or just: import 'cross-fetch/polyfill';

fetch('//api.github.com/users/lquixada')
  .then(res => {
    if (res.status >= 400) {
      throw new Error("Bad response from server");
    }
    return res.json();
  })
  .then(user => {
    console.log(user);
  })
  .catch(err => {
    console.error(err);
  });

With async/await:

import fetch from 'cross-fetch';
// Or just: import 'cross-fetch/polyfill';

(async () => {
  try {
    const res = await fetch('//api.github.com/users/lquixada');

    if (res.status >= 400) {
      throw new Error("Bad response from server");
    }

    const user = await res.json();

    console.log(user);
  } catch (err) {
    console.error(err);
  }
})();

This helped for metaweather api, well explained in github documentation. Thanks for Sharing
Using crossfetch's polyfill also worked for me using typescript and node and receiving the ReferenceError: fetch is not defined error from amazon-cognito-identity-js.
K
Khuram Niaz

If you want to avoid npm install and not running in browser, you can also use nodejs https module;

const https = require('https')
const url = "https://jsonmock.hackerrank.com/api/movies";
https.get(url, res => {
  let data = '';
  res.on('data', chunk => {
    data += chunk;
  });
  res.on('end', () => {
    data = JSON.parse(data);
    console.log(data);
  })
}).on('error', err => {
  console.log(err.message);
})

Just remember to add .end() right at the bottom of this snippet to actually start the request off. See docs
o
ofir_aghai

You should add this import in your file:

import * as fetch from 'node-fetch';

And then, run this code to add the node-fetch:
$ yarn add node-fetch

If you're working with typescript, then install node-fetch types:
$ yarn add @types/node-fetch


If I import in this way and use typescript, I have this error TS2349: This expression is not callable. Type 'typeof import("/node_modules/@types/node-fetch/index")' has no call signatures.. It works only with require.
run $ yarn add @types/node-fetch to installing node-fetch types
of course I did, it is about using es6 import vs require. seems like node-fetch does not support this modern import syntaxis.
T
Tomerikoo

Node.js hasn't implemented the fetch() method, but you can use one of the external modules of this fantastic execution environment for JavaScript.

In one of the other answers, "node-fetch" is cited and that's a good choice.

In your project folder (the directory where you have the .js scripts) install that module with the command:

npm i node-fetch --save

Then use it as a constant in the script you want to execute with Node.js, something like this:

const fetch = require("node-fetch");

require() of ES module is not supported
R
Rafael Lourenço

EDITED - New Solution

To use the latest version (3.0.0) you must do the import like this:

const fetch = (url) => import('node-fetch').then(({default: fetch}) => fetch(url));

Old Anwser:

This may not be the best solution, but if you install this version :

npm install node-fetch@1.7.3

you can now use the line below without error's.

const fetch = require("node-fetch");

Is there a specific reason to use this older version instead of using the latest one, especially noting this vulnerability with it?
@LW001 When I had this problem this was a quick fix I did. If you use the new version(3.0.0) , it will get an error in import and then you'll get another one that says "fetch is not a function". As you said, this version has vulnerabilities and you should always use the latest one, so I edited my answer to solve the problem.
In your code (new one) the Promise will not work. If you need to use require go with version 2 which will get critical updates: "If you cannot switch to ESM, please use v2 which remains compatible with CommonJS. Critical bug fixes will continue to be published for v2." node-fetch@2
T
Tomerikoo

You have to use the isomorphic-fetch module to your Node project because Node does not contain Fetch API yet. For fixing this problem run below command:

npm install --save isomorphic-fetch es6-promise

After installation use below code in your project:

import "isomorphic-fetch"

Not actively maintained; has been years since the last accepted PR. github.com/matthew-andrews/isomorphic-fetch/graphs/contributors
FYI, this can lead to difficult in typescript projects because this library does not provide proper types. An easier router is to use cross-fetch which is very similar but plays nice with typescript. For a react app where you are assuming that normal fetch will be available in the browser you can make this a dev dependency and use import 'cross-fetch/polyfill'; in test setup to smooth the rough edges of the testing environment.
k
krl

fetch came to Node v17 under experimental flag --experimental-fetch

It will be available in Node v18 without the flag.

https://github.com/nodejs/node/pull/41749#issue-1118239565

You no longer need any additional package to be installed


Node 18 is out, and it is still experimental.
M
Mohammad Quanit

Best one is Axios library for fetching. use npm i --save axios for installng and use it like fetch, just write axios instead of fetch and then get response in then().


This is happening more in build time, while your comment is good, the problem is different to what you proposed
c
closedloop

For those also using typescript on node-js and are getting a ReferenceError: fetch is not defined error

npm install these packages:

    "amazon-cognito-identity-js": "3.0.11"
    "node-fetch": "^2.3.0"

Then include:

import Global = NodeJS.Global;
export interface GlobalWithCognitoFix extends Global {
    fetch: any
}
declare const global: GlobalWithCognitoFix;
global.fetch = require('node-fetch');

amazon-cognito-identity-js is not relevant to this question and not needed to install to solve this error. It is also not related to typescript.
Hi! So i am having exactly the same issue, but this still din't fix anything, do you have any other work around?
I'm also looking for a work-around. Doing import fetch from 'node-fetch'; instead is one fix for typescript
E
Expert Ngobeni

It seems fetch support URL scheme with "http" or "https" for CORS request.

Install node fetch library npm install node-fetch, read the file and parse to json.

const fs = require('fs')
const readJson = filename => {
  return new Promise((resolve, reject) => {
    if (filename.toLowerCase().endsWith(".json")) {
      fs.readFile(filename, (err, data) => {
        if (err) {
          reject(err)
          return
        }
        resolve(JSON.parse(data))
      })
    }
    else {
      reject(new Error("Invalid filetype, <*.json> required."))
      return
    }
  })
}

// usage
const filename = "../data.json"
readJson(filename).then(data => console.log(data)).catch(err => console.log(err.message))

E
Endless

In node.js you can use : node-fetch package

npm i node-fetch

then :

import fetch from 'node-fetch';

here is a full sample in (nodejs) :

import fetch from "node-fetch";

const fetchData = async () => {
  const res = await fetch("https://restcountries.eu/rest/v2/alpha/col"); // fetch() returns a promise, so we need to wait for it

  const country = await res.json(); // res is now only an HTTP response, so we need to call res.json()

  console.log(country); // Columbia's data will be logged to the dev console
};

fetchData();

n
nabais

In HackerRank, some libraries are installed by default and some are not.

Because it is running Node.js, the fetch API is not installed by default.

The best thing for you to do is to check whether the libraries are or not installed.

on the top of the exercise, there is the following:

const https = require('https');

Please try to add this to the top as well:

const axios = require('axios');

and then run the code.

If there is a compilation error, then it's not available, otherwise you can use axios, which is a good alternative to fetch

To use it with then, you can:

function getMovieTitles(substr){
  axios.get(url)
    .then(function(response){
      console.log(response.data);
    })
}

or taking advantage of the async/await

async function getMovieTitles(substr){
  let response = await axios.get(url)
  console.log(response.data);
}

a
asma

This is the related github issue This bug is related to the 2.0.0 version, you can solve it by simply upgrading to version 2.1.0. You can run npm i graphql-request@2.1.0-next.1


P
Pavel Muzik

The following works for me in Node.js 12.x:

npm i node-fetch;

to initialize the Dropbox instance:

var Dropbox = require("dropbox").Dropbox;
var dbx = new Dropbox({
   accessToken: <your access token>,
   fetch: require("node-fetch")    
});

to e.g. upload a content (an asynchronous method used in this case):

await dbx.filesUpload({
  contents: <your content>,
  path: <file path>
});

Y
YeonCheol Jang

For me these are looking more simple.

npm install node-fetch
import fetch from "node-fetch";

V
Venryx

There are actually a lot of different libraries for making fetch available in the browser.

The main ones I'm aware of are:

node-fetch

cross-fetch

whatwg-fetch

isomorphic-fetch

I currently use node-fetch, and it has worked fine, but I don't really know which one is "the best". (though the openbase.com pages I linked to provide some metadata on usage [eg. Github stars, npm downloads], which can help)


P
Piyush Aggarwal

This answer does not directly answer this question. Instead it suggests for an alternative.

Why? Because the using 'node-fetch' is getting complicated since you cannot import the updated versions using const fetch = require('node-fetch') . You will have to do more things to just make it work.

Try using axios package:

Simple installation npm i axios code for fetching goes like

const response = await axios.get(url).then(res => res.data)

R
Radim Šafrán

This worked for me:

const nodeFetch = require('node-fetch') as typeof fetch;

L
Lonely

Solution July 2022, Node Version 18.4.0

fetch is still experimental, but I have a step-by-step recipe for you. You don't have to install anything additionally.

Step 1: Imagine we want to fetch multiple URLs

I use a standard open API (Star Wars API):

const starWarsPeople = [
  'https://swapi.dev/api/people/1/',
  'https://swapi.dev/api/people/2/',
  'https://swapi.dev/api/people/3/',
];

Step 2: We create a vanilla custom asynchronous Iterator:

That is not necessary, but we want to do it, because in this way every single step is in our control:

starWarsPeople[Symbol.asyncIterator] = () => {
  let index = 0;

  return {
    async next() {
      if (index === starWarsPeople.length) {
        return { done: true };
      }

      const url = starWarsPeople[index];
      index++;
      const response = await fetch(url);

      if (!response.ok) {
        throw new Error('Cannot retrieve Url: ' + url);
      }

      return {
        value: await response.json(),
        done: false,
      };
    },
  };
};

Step 3: We use an IIFE (Immediately-Invoked Function Expression)

Be aware of () in the last line.

(async function () {
  try {
    for await (const person of starWarsPeople) {
      console.log('Person: ', person?.name);
    }
  } catch (err) {
    console.error('Error: ', err);
  }
})();

Last but least: the whole example online (StackBlitz)

And this is your `tsconfig.json``

{
  "compilerOptions": {
    "target": "esnext",
    "lib": ["ESNext", "DOM"],
    "module": "esnext",
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipDefaultLibCheck": true,
    "skipLibCheck": true
  }
}

1
19_520 Karthikeya

Just make your app.js file Extension as app.mjs and the problem will be solved!!!:)


J
JFM

Might sound silly but I simply called npm i node-fetch --save in the wrong project. Make sure you are in the correct directory.


You must not --save what is required only for tests. Use --save-dev instead.
H
Henry Ecker

If need install:

npm install --save global-fetch

then

var fetch = require("node-fetch");

Is it global-fetch or node-fetch?
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.