facebook / facebook-nodejs-business-sdk

Node.js SDK for Meta Marketing APIs
https://developers.facebook.com/docs/business-sdk
Other
499 stars 227 forks source link

Fetching data is broadly broken with this repository #298

Closed dannyjlaurence-exp closed 1 month ago

dannyjlaurence-exp commented 1 month ago

Which SDK version are you using?

v20.0.2

What's the issue?

The default data: {} parameter is making all get requests fail to load data.

Steps/Sample code to reproduce the issue

const getActiveFacebookCampaigns = async () => {
  adsSdk.FacebookAdsApi.init(FACEBOOK_SYSTEM_USER_TOKEN);
  const account = new adsSdk.AdAccount(`act_${FACEBOOK_ADS_ACCOUNT_ID}`);

  let campaigns = await account.getCampaigns(
    [
      adsSdk.Campaign.Fields.daily_budget,
      adsSdk.Campaign.Fields.status,
      adsSdk.Campaign.Fields.name,
      adsSdk.Campaign.Fields.special_ad_categories,
    ],
    {
      limit: 10,
    }
  );

  return campaigns;
};

export const getAds = async () => {
  console.log("starting to get campaigns");
  let campaigns;
  try {
    campaigns = await getActiveFacebookCampaigns();
  } catch (e) {
    console.error(e);
  }
  console.log(campaigns);
};

Observed Results:

Here is the error output of running the above code:

Error
    at FacebookRequestError.FacebookError [as constructor] (/Users/dannyjlaurence/Git/miscellaneous-files/js-scripts/facebook-ads/node_modules/facebook-nodejs-business-sdk/dist/cjs.js:351:16)
    at new FacebookRequestError (/Users/dannyjlaurence/Git/miscellaneous-files/js-scripts/facebook-ads/node_modules/facebook-nodejs-business-sdk/dist/cjs.js:373:129)
    at /Users/dannyjlaurence/Git/miscellaneous-files/js-scripts/facebook-ads/node_modules/facebook-nodejs-business-sdk/dist/cjs.js:676:15
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  message: 'An unknown error has occurred.',
  status: 500,
  response: {
    message: 'An unknown error has occurred.',
    type: 'OAuthException',
    code: 1,
    fbtrace_id: 'XXXXX'
  },

Expected Results:

I'd expect the campaigns to be outputted.

The issue:

The following code in the HTTP request promise function (I am including the compiled version that is in the SDK, since ultimately that's what is being used at runtime):

    key: 'requestPromise',
    value: function requestPromise(method, url, data, files) {
      var useMultipartFormData = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
      var showHeader = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;

      var options = {
        method: method,
        url: url,
        baseURL: FacebookAdsApi.GRAPH,
        json: !useMultipartFormData,
        headers: { 'User-Agent': 'fbbizsdk-nodejs-v' + FacebookAdsApi.SDK_VERSION },
        data: Object,
        resolveWithFullResponse: showHeader
      };
      // Prevent null or undefined input
      // because it can be merged with the files argument later
      if (!data) {
        data = {};
      }

      options.data = data;

      // Handle file attachments if provided
      if (useMultipartFormData || files && Object.keys(files).length > 0) {
        // Use formData instead of body (required by the request-promise library)
        options.data = Object.assign(data, files);
        delete options.data;
      }

      return axios(options).catch(function (response) {
        throw response;
      });
    }

You can see that the options.data will always be {}, which is what causes the error.

The minimum reproduction here is this:

curl --location --request GET 'https://graph.facebook.com/v19.0/<campaign id>?fields=status&access_token=<access token>' \
--header 'User-Agent: fbbizsdk-nodejs-v20.0.2' \
--header 'Content-Type: application/json' \
--data '{}'

Where you replace the with any campaign (or, just like, anything on the graph) and the with a valid access token.

You will see the 500. If instead, you do this:

curl --location --request GET 'https://graph.facebook.com/v19.0/<campaign id>?fields=status&access_token=<access token>' \
--header 'User-Agent: fbbizsdk-nodejs-v20.0.2' \

It will work

pedroida commented 1 month ago

I'm also facing this problem with the v20.* all the get requests with no data as response are throwing unknown error

asouza commented 1 month ago

I think I am facing a similar problem. But the problem only occur when I try to get insights from AdSets or Ads. When I try to invoke campaing.getAdSet or adSet.getAds I get 500 an Unknown Error. But, when I copy the url and access directly from the browser, the response is ok.

dannyjlaurence-exp commented 1 month ago

I think I am facing a similar problem. But the problem only occur when I try to get insights from AdSets or Ads. When I try to invoke campaing.getAdSet or adSet.getAds I get 500 an Unknown Error. But, when I copy the url and access directly from the browser, the response is ok.

That's because your browser doesn't issue the request with the data param.

I've done a little bit of research here, and my initial diagnosis might be off by a bit:

So, really, the minimum reproduction is technically this:

const axios = require('axios');
let data = JSON.stringify({});

let config = {
  method: 'get',
  maxBodyLength: Infinity,
  url: 'https://graph.facebook.com/v19.0/<node_id>?fields=status&access_token=<access_token>',
  headers: { 
    'User-Agent': 'fbbizsdk-nodejs-v19.0.3', 
    'Content-Type': 'application/json'
  },
  data : data
};

axios.request(config)
.then((response) => {
  console.log(JSON.stringify(response.data));
})
.catch((error) => {
  console.log(error);
});

and not cURL which is actually saying "POSTs to load data doesn't work."

This all still confirms the initial problem, but wanted to share some interesting findings.

felipealpino commented 1 month ago

I implemented a bypass that is apparently working, so you can try doing the same:

You will be running a script that is going to modify some files in node_modules/facebook-nodejs-business-sdk/dist

image

SCRIPT:

const fs = require('fs');
const path = require('path');

// Define the directory and files
const directoryPath = path.join(__dirname, 'node_modules/facebook-nodejs-business-sdk/dist');
const filesToModify = ['umd.js', 'iife.js', 'globals.js', 'es.js', 'cjs.js'];

// Define the code block you're searching for
const searchCodeBlock = `      if (!data) {
        data = {};
      }

      options.data = data;

      // Handle file attachments if provided
      if (useMultipartFormData || files && Object.keys(files).length > 0) {
        // Use formData instead of body (required by the request-promise library)
        options.data = Object.assign(data, files);
        delete options.data;
      }`;

// Define the code block to add
const additionalCode = `      if (method === 'GET') {
        delete options.data;
      }
`;

// Function to modify the file
function modifyFile(filePath) {
  fs.readFile(filePath, 'utf8', (err, data) => {
    if (err) {
      console.error(`Error reading file ${filePath}:`, err);
      return;
    }

    // Check if the file contains the searchCodeBlock
    if (data.includes(searchCodeBlock)) {
      // Append the additionalCode after the searchCodeBlock
      const updatedData = data.replace(searchCodeBlock, searchCodeBlock + '\n' + additionalCode);

      // Write the modified data back to the file
      fs.writeFile(filePath, updatedData, 'utf8', (err2) => {
        if (err2) {
          console.error(`Error writing to file ${filePath}:`, err2);
          return;
        }

        console.log(`Successfully updated ${filePath}`);
      });
    } else {
      console.log(`Code block not found in ${filePath}`);
    }
  });
}

// Modify each file
filesToModify.forEach((file) => {
  const filePath = path.join(directoryPath, file);
  modifyFile(filePath);
});
danielvoelk commented 1 month ago

For me it was working until yesterday evening. Now I have the same issue. All requests fail with error OAuthException

// thise one works
const metaAdAccount: AdAccount = new AdAccount(adAccount.ad_account_id);

// this one fails
const accountInfo = await metaAdAccount.read(['timezone_name, currency']);
const timezone = accountInfo.timezone_name;
KonstantinYugay commented 1 month ago

"facebook-nodejs-business-sdk": "^20.0.3" this issue NOT fixed!

danielvoelk commented 1 month ago

Yes, I also updated and the issue still occurs. The sdk is not usable like that.

satwikareddy3 commented 1 month ago

Thank you for bringing this to our attention. We have identified and resolved the backend issue that was causing the problem. As the issue has been resolved, we will be closing this issue. If you continue to experience any issues, please feel free to reopen the issue.