Почему пример google calendar api nodejs не работает, если я делаю это таким образом? - PullRequest
0 голосов
/ 06 мая 2018

На основе примера быстрого запуска nodejs (учетные данные заменены на фиктивные) здесь

Ниже приведен код, который работает:

const fs = require('fs');
const mkdirp = require('mkdirp');
const readline = require('readline');
const {google} = require('googleapis');
const OAuth2Client = google.auth.OAuth2;
const SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'];
const TOKEN_PATH = 'credentials.json';

// Load client secrets from a local file.
fs.readFile('client_secret.json', (err, content) => {
  if (err) return console.log('Error loading client secret file:', err);
  // Authorize a client with credentials, then call the Google Drive API.
  authorize(JSON.parse(content), listEvents);
});

/**
 * Create an OAuth2 client with the given credentials, and then execute the
 * given callback function.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback to call with the authorized client.
 */
function authorize(credentials, callback) {
  const {client_secret, client_id, redirect_uris} = credentials.web;
  const oAuth2Client = new OAuth2Client(client_id, client_secret, redirect_uris[0]);

  // Check if we have previously stored a token.
  fs.readFile(TOKEN_PATH, (err, token) => {
    if (err) return getAccessToken(oAuth2Client, callback);
    oAuth2Client.setCredentials(JSON.parse(token));

    // THIS WORKS IF ITS HERE AND PASSED IN CALLBACK
    let client = new OAuth2Client("484407463774-e7biatgmpns9jcpakr5g0sed8fab376u.apps.googleusercontent.com", "722_fI1u2abNM3tL-VbCuZfF", "http://localhost:1337/api/v1/oauthCallback");
    client.setCredentials({
      "access_token": "ya29.GluyBSUYvP_Gi4_SdJHabcJmXUjHnw34MfMBJ8tzROflqyR9dFMDOh_AYh9dmL4FSNDiva_nAcWYCM9m5jBwaL3pWfSm_wv0IybUUdebt66gDakdFXL0o8Mr-0Ge",
      "expiry_date": 1525551674971,
      "token_type": "Bearer",
      "refresh_token": "1/Ug8agC92PkJRXEDLP1inlHcAh4MBP1SLjNoylPJrmfg"
    });


    callback(client);
  });
}

/**
 * Get and store new token after prompting for user authorization, and then
 * execute the given callback with the authorized OAuth2 client.
 * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
 * @param {getEventsCallback} callback The callback for the authorized client.
 */
 function getAccessToken(oAuth2Client, callback) {
  const authUrl = oAuth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: SCOPES,
  });
  console.log('Authorize this app by visiting this url:', authUrl);
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  rl.question('Enter the code from that page here: ', (code) => {
    rl.close();
    oAuth2Client.getToken(code, (err, token) => {
      if (err) return callback(err);
      oAuth2Client.setCredentials(token);
      // Store the token to disk for later program executions
      fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
        if (err) console.error(err);
        console.log('Token stored to', TOKEN_PATH);
      });
      callback(oAuth2Client).catch(console.error);
    });
  });
}

/**
 * Lists the next 10 events on the user's primary calendar.
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 */
function listEvents(auth) {

  const calendar = google.calendar({ version: 'v3', auth });
  calendar.events.list({
    calendarId: 'primary',
    timeMin: (new Date()).toISOString(),
    maxResults: 10,
    singleEvents: true,
    orderBy: 'startTime',
  }, (err, {data}) => {
    if (err) return console.log('The API returned an error: ' + err);
    const events = data.items;
    if (events.length) {
      console.log('Upcoming 10 events:');
      events.map((event, i) => {
        const start = event.start.dateTime || event.start.date;
        console.log(`${start} - ${event.summary}`);
      });
    } else {
      console.log('No upcoming events found.');
    }
  });


}

Итак, в приведенном выше коде мы сначала находим учетные данные из файла credentials.json. Я просто жестко закодировал их для удобства в authorize()

let client = new OAuth2Client("484407463774-e7biatgmpns9jcpakr5g0sed8fab376u.apps.googleusercontent.com", "722_fI1u2abNM3tL-VbCuZfF", "http://localhost:1337/api/v1/oauthCallback");
        client.setCredentials({
          "access_token": "ya29.GluyBSUYvP_Gi4_SdJHabcJmXUjHnw34MfMBJ8tzROflqyR9dFMDOh_AYh9dmL4FSNDiva_nAcWYCM9m5jBwaL3pWfSm_wv0IybUUdebt66gDakdFXL0o8Mr-0Ge",
          "expiry_date": 1525551674971,
          "token_type": "Bearer",
          "refresh_token": "1/Ug8agC92PkJRXEDLP1inlHcAh4MBP1SLjNoylPJrmfg"
        });

Но если я переместу вышеупомянутые строки в listEvents() следующим образом:

const fs = require('fs');
const mkdirp = require('mkdirp');
const readline = require('readline');
const {google} = require('googleapis');
const OAuth2Client = google.auth.OAuth2;
const SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'];
const TOKEN_PATH = 'credentials.json';

// Load client secrets from a local file.
fs.readFile('client_secret.json', (err, content) => {
  if (err) return console.log('Error loading client secret file:', err);
  // Authorize a client with credentials, then call the Google Drive API.
  authorize(JSON.parse(content), listEvents);
});

/**
 * Create an OAuth2 client with the given credentials, and then execute the
 * given callback function.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback to call with the authorized client.
 */
function authorize(credentials, callback) {
  const {client_secret, client_id, redirect_uris} = credentials.web;
  const oAuth2Client = new OAuth2Client(client_id, client_secret, redirect_uris[0]);

  // Check if we have previously stored a token.
  fs.readFile(TOKEN_PATH, (err, token) => {
    if (err) return getAccessToken(oAuth2Client, callback);
    oAuth2Client.setCredentials(JSON.parse(token));


    callback(null);
  });
}

/**
 * Get and store new token after prompting for user authorization, and then
 * execute the given callback with the authorized OAuth2 client.
 * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
 * @param {getEventsCallback} callback The callback for the authorized client.
 */
 function getAccessToken(oAuth2Client, callback) {
  const authUrl = oAuth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: SCOPES,
  });
  console.log('Authorize this app by visiting this url:', authUrl);
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  rl.question('Enter the code from that page here: ', (code) => {
    rl.close();
    oAuth2Client.getToken(code, (err, token) => {
      if (err) return callback(err);
      oAuth2Client.setCredentials(token);
      // Store the token to disk for later program executions
      fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
        if (err) console.error(err);
        console.log('Token stored to', TOKEN_PATH);
      });
      callback(oAuth2Client).catch(console.error);
    });
  });
}

/**
 * Lists the next 10 events on the user's primary calendar.
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 */
function listEvents(auth) {
 // THIS DOES NOT WORK 
 let client = new OAuth2Client("480557463774-e7biatgmpns9jcpakran0sed8f55376u.apps.googleusercontent.com", "722_fBsu2ECNM3tL-VbCuZfF", "http://localhost:1337/api/v1/oauthCallback");
  client.setCredentials({
    "access_token": "ya29.GluyBSUYvP_Gi4_SdJHsuPJmXUjHdd34MfMBJ8tzROflqyR9dFMDOh_AYh9dmL4FSNDiva_nAcWYCM9m5jBwaL3pWfSm_wv0IybUUORbt66gDakdFXL0o8Mr-0Ge",
    "expiry_date": 1525551674971,
    "token_type": "Bearer",
    "refresh_token": "1/Ug8MhC92ddJRXEDLP1inlHcAh4MBP1SLjNoylPJrmfg"
  });

  const calendar = google.calendar({ version: 'v3', client });
  calendar.events.list({
    calendarId: 'primary',
    timeMin: (new Date()).toISOString(),
    maxResults: 10,
    singleEvents: true,
    orderBy: 'startTime',
  }, (err, {data}) => {
    if (err) return console.log('The API returned an error: ' + err);
    const events = data.items;
    if (events.length) {
      console.log('Upcoming 10 events:');
      events.map((event, i) => {
        const start = event.start.dateTime || event.start.date;
        console.log(`${start} - ${event.summary}`);
      });
    } else {
      console.log('No upcoming events found.');
    }
  });


}

Тогда он больше не работает и выдает эту ошибку:

(node:95252) UnhandledPromiseRejectionWarning: TypeError: Cannot destructure property `data` of 'undefined' or 'null'.
    at calendar.events.list (C:\Users\rahulserver\Desktop\gcalapinodejs\quickstart.js:87:6)
    at C:\Users\rahulserver\Desktop\gcalapinodejs\node_modules\google-auth-library\build\src\transporters.js:74:17
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
(node:95252) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside o
f an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:95252) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections tha
t are not handled will terminate the Node.js process with a non-zero exit code.

ИМО Я делаю одно и то же в любом случае. В первом случае я передаю клиента в качестве параметра для обратного вызова. Во-вторых, я передаю null обратному вызову и создаю экземпляр oauth-клиента в самом обратном вызове. Не уверен, что «таинственная» вещь происходит во втором подходе, из-за которого код больше не работает.

Ответы [ 2 ]

0 голосов
/ 07 мая 2018

Ну, я понял это.

вместо const calendar = google.calendar({ version: 'v3', client });

должно быть const calendar = google.calendar({ version: 'v3', auth: client });

Так что синтаксис сокращений объектов es6 иногда может сбивать с толку!

0 голосов
/ 07 мая 2018

Вы получаете какую-то ошибку, которая делает второй аргумент в обратном вызове от calendar.events.list() undefined.

Имейте в виду, что этот обратный вызов принимает форму (err, {data}) => {, поэтому в случае ошибки у вас не будет второго аргумента. Тем не менее, вы все еще пытаетесь его разрушить, поэтому ваша ошибка.

Простое исправление - применить аргумент по умолчанию. Это заставит его использовать пустой объект в случае ошибки:

(err, { data } = {}) => {

В качестве альтернативы, вы можете уничтожить его после проверки ошибок. Лично я фанат стандартных аргументов.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...