While testing my node app on Safari, routes that are stored in my browser's history seem to get pinged twice per request, and carry out all of the method calls associated with that path twice (the browser itself only seems to receive one response, though).
This is primarily an issue because I am interfacing with the Google Calendar API in order to add a new calendar event-- right now the test event gets added twice when I try to add it once. So far this only seems to happen in Safari (but I've only tested in Safari and Chrome).
What actually happens:
I begin typing "localhost:3000/add," the browser predicts the last two letters of the path, and as soon as the predictive text appears, I can see via console.log that the app executes the path defined at app.get('/add'), even though none of this activity is apparent on the browser end (e.g., the browser doesn't refresh and display the information it received from an API call, even though that info is being logged, and sending info to res is part of the same function causing the log statements).
Then, when I actually enter the address, the path executes again, but this time the browser refreshes upon receiving a response, and displays new data.
test.js:
"use strict";
const express = require('express');
const app = express();
//must be initialized with .init()
const CalendarManager = require('./GoogleCalApi.js');
const calendar = new CalendarManager();
require('dotenv').config('./.env');
calendar.init(process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
process.env.REDIRECT_URL + '/oauthcallback',
(m) => console.log);
app.get('/', (req, res) => {
res.sendFile(process.cwd() + '/views/test.html')
})
app.get('/verify', (req, res) => {
calendar.getAuthUrl((err, url)=>{ err ? res.send('error getting auth url') :
res.redirect(url) });
})
app.get('/oauthcallback', (req, res) => {
console.log('callback ping')
let done = (err, message) => message ? res.send(message) : res.send(err);
calendar.storeCred(req.query.code, done)
})
app.get('/add', (req, res) => {
console.log('add route ping')
let event = {
'summary': 'TestEvent',
'start': {
'date': '2019-07-13'
},
'end': {
'date': '2019-07-14'
}
}
calendar.addEvent(event, (err, data) => { res.send(err ? err : data) });
})
app.listen(3000, () => {console.log('listening on port 3000')})
GoogleCalApi.js:
const {google} = require('googleapis');
function GoogleCalendarApi () {
this.initialized = false;
this.oauth2Client = null;
this.url = null;
this.token = null;
this.calendar = null;
this.init = function (clientId, clientSecret, redirect_url, done) {
this.oauth2Client = new google.auth.OAuth2(
clientId,
clientSecret,
redirect_url
);
this.scopes = ['https://www.googleapis.com/auth/calendar'];
this.url = this.oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: this.scopes
})
//listeners
this.oauth2Client.on('tokens', (tokens) => {
console.log('token event:', this.token)
if (tokens.refresh_token) {
this.token = tokens.refresh_token;
console.log('refresh: ' + tokens.refresh_token)
}
console.log('auth token: ' + tokens.access_token)
})
console.log('initialized', this.oauth2Client)
this.initialized = true;
done('initialized');
};
/**
* @param done: callback function that can handle two params: error and url
* -error should be null, or an error message
* -url should be an address for Google Cloud's authentication process
**/
this.getAuthUrl = (done) => { this.url ? done(null, this.url) : done('error: url not defined') }
this.storeCred = function (code, done) { //code from req.query.code
async function cred (auth) {
try {
console.log('storeCred ping')
const {tokens} = await auth.getToken(code)
auth.setCredentials(tokens)
console.log('tokens', tokens)
done(null, 'authenticated')
} catch (err) {
console.log('error in cred:', err)
done(err)
}
}
try { cred(this.oauth2Client) } catch (err) { done(err) }
}
this.addEvent = function (event, done) {
console.log('add event ping')
if (this.calendar === null) this.calendar = google.calendar({version: 'v3', auth: this.oauth2Client});
this.calendar.events.insert({
auth: this.oauth2Client,
calendarId: 'primary',
resource: event
}, (err, data) => { done(null, data) })
}
} //end constructor
module.exports = GoogleCalendarApi;
As I described above, I'm seeing:
add route ping
add event ping
add route ping
add event ping
in the console, when I should only be seeing:
add route ping
add event ping
And the google calendar I'm updating has a duplicate event when I visit the calendar page itself.
(Also, I'm pretty unfamiliar with using markdown, so if formatting for the code portion of this question fails, I apologize in advance, and please feel free to ignore the post until I'm able to fix it)