Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

TypeError: fetch is not a function

    const express = require('express');
    const router = express.Router();
    const fetch = import('node-fetch');
    const btoa = require('btoa');

    const CLIENT_ID = 'this is an id';
    const CLIENT_SECRET = 'this is a secret';
    const redirect = encodeURIComponent('http://localhost:8080/discord/callback');

    router.get('/login', (_req, res) => {
        res.redirect(`https://discordapp.com/api/oauth2/authorize?client_id=${CLIENT_ID}&scope=identify&response_type=code&redirect_uri=${redirect}`);
    });

    router.get('/callback', (req, res) => {
        if (!req.query.code) throw new Error('NoCodeProvided');
        const code = req.query.code;
        const creds = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
        const response = fetch(`https://discordapp.com/api/oauth2/token?grant_type=authorization_code&code=${code}&redirect_uri=${redirect}`,
            {
                method: 'POST',
                headers: {
                    Authorization: `Basic ${creds}`,
                },
            });
        const json = response.json();
        console.log(json);
        res.redirect(`/?token=${json.access_token}`);
    });

    module.exports = router;

I know js very poorly and don’t understand why node-fetch is no longer a function.

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

The node-fetch documentation shows you how to handle this:

// mod.cjs
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => > fetch(...args));

(I had just come up with that myself, when to check whether it dida default export or a named one, and ran across that when searching for import.)

For instance, you might put that in my-fetch.js and do:

const fetch = require("./my-fetch.js");

What that does:

  • Gets the promise for the module from import().
  • Exports a stand-in fetch function.
  • When the stand-in function is called, it waits for the promise from import() to be fulfilled with the module namespace object of the node-fetch module, gets the fetch function from the default property on it, and passes on the call to that.

That’s fairly seamless (one very quick extra async tick), since fetch returns a promise.


Separately, it looks like you’re using fetch incorrectly. fetch returns a promise, so you have to consume the promise. You can do that with an async function or explicitly with .then and .catch:

With an async function and await:

router.get('/callback', async (req, res) => {
    // When passing an `async` function to Express, it's important to ensure that
    // you handle **all** errors locally, because Express won't do anything with
    // the promise the function returns, so rejections will not be handled.
    try {
        if (!req.query.code) throw new Error('NoCodeProvided');
        const code = req.query.code;
        const creds = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
        const response = await fetch(`https://discordapp.com/api/oauth2/token?grant_type=authorization_code&code=${code}&redirect_uri=${redirect}`, {
            method: 'POST',
            headers: {
                Authorization: `Basic ${creds}`,
            },
        })
        if (!response.ok) {
            throw new Error(`HTTP error ${response.status}`);
        }
        const data = await response.json();
        res.redirect(`/?token=${json.access_token}`);
    } catch (error) {
        // ...send an appropriate error response...
    }
});

Or with .then and .catch:

router.get('/callback', (req, res) => {
    if (!req.query.code) throw new Error('NoCodeProvided'); // Don't do this, send an error response instead
    const code = req.query.code;
    const creds = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
    fetch(`https://discordapp.com/api/oauth2/token?grant_type=authorization_code&code=${code}&redirect_uri=${redirect}`, {
        method: 'POST',
        headers: {
            Authorization: `Basic ${creds}`,
        },
    })
    .then(response => {
        if (!response.ok) {
            throw new Error(`HTTP error ${response.status}`);
        }
        return response.json();
    })
    .then(data => {
        res.redirect(`/?token=${json.access_token}`);
    })
    .catch(error => {
        // ...send an appropriate error response...
    });
});
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading