Search code examples
javascriptnode.jsecmascript-6node-fetch

Node-Fetch unhandled promise rejection (can't catch it)


I'm struggling for 2 days on this one so I try asking here:

I have a nodejs script using node-fetch to make queries ton an API. However, I've tried adding catch blocks everywhere but it seems I didn't suceeded in ahndling the error.

Here is my function:

fetchUrl.get = async (url, params = false, headers = false) => {
        let defaultOptions = {
            method: "GET",
        };
    
        let finalUrl = new URL(url);
        Object.keys(params).forEach((key) =>
            finalUrl.searchParams.append(key, params[key])
        );
    
        let finalHeaders = {};
    
        if (headers != null && headers != false && Object.keys(headers).length > 0) {
            Object.keys(headers).forEach((headerKey) => {
                finalHeaders[headerKey] = headers[headerKey];
            });
        }
    
        defaultOptions["headers"] = finalHeaders;
    
        let result = null;
    
        try {
            result = await fetch(finalUrl, defaultOptions)
                .then((res) => {
                    if (res.status == 200) {
                        return {
                            success: true,
                            text: res.text(),
                        };
                    } else {
                        console.log("ERROR during Fetch: " + res.status);
                        console.error(finalUrl);
                        console.error(params);
                        res.text().then((err) => {
                            console.error(err);
                        });
                        return {
                            success: false,
                        };
                    }
                })
                .then((resParsed) => {
                    if (resParsed.success) {
                        return resParsed.text;
                    } else {
                        return false;
                    }
                });
        } catch (err) {
            throw err;
        }
    
        return result;
    };

And this is the error I get:

(node:2272) UnhandledPromiseRejectionWarning: FetchError: request to http://gdsfdfs.com/ failed, reason: getaddrinfo ENOTFOUND gdsfdfs.com
    at ClientRequest.<anonymous> (file:///home/kashnars/pearlv2/node_modules/node-fetch/src/index.js:108:11)
    at ClientRequest.emit (events.js:375:28)
    at Socket.socketErrorListener (_http_client.js:475:9)
    at Socket.emit (events.js:375:28)
    at emitErrorNT (internal/streams/destroy.js:106:8)
    at emitErrorCloseNT (internal/streams/destroy.js:74:3)
    at processTicksAndRejections (internal/process/task_queues.js:82:21)
(node:2272) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 50)

I know the URL is wrong, it's just for testing purposes. I need to catch the error.

Someone having the solution?

Thanks in advance,


Solution

  • The issue is that you throw an error, which is a Promise rejection in an async function

    The calling function needs to handle the rejection

    Now, since all you do in the catch is rethrow the error, no need to use try/catch at all

    More simplifiction of your code is possible - but, basically, from the await it should go like

    const res = await fetch(finalUrl, defaultOptions);
    if (res.status == 200) {
        return res.text();
    }
    console.log("ERROR during Fetch: " + res.status);
    console.log(finalUrl);
    console.log(params);
    const err = await res.text();
    console.error(err);
    return false;
    

    with no try/catch

    Alternatively, if you want this function to handle the network error, and return false, just like when status !== 200

    try {
        const res = await fetch(finalUrl, defaultOptions);
        if (res.status == 200) {
            return res.text();
        }
        console.log("ERROR during Fetch: " + res.status);
        console.log(finalUrl);
        console.log(params);
        const err = await res.text();
        throw err;
    } catch(err) {
        console.error(err);
        return false;
    }
    

    as a bonus, the code above the try { or await fetch can be simplified to

    fetchUrl.get = async (url, params = false, headers = false) => {
        const defaultOptions = { 
            method: "GET",
            headers: {...(headers ?? {}) }
        };
        
        const finalUrl = new URL(url);
        Object.entries(params ?? {}).forEach(([key, value]) => {
            finalUrl.searchParams.append(key, value)
        });