CORS using node_helper.js for Uber and Lyft APIs



  • Hi all,

    I have a bit of programming experience (mostly C and python) but I have never worked with javascript. I am trying to create a module to communicate with the Uber and Lyft APIs. Initially I was trying to do something like this for Lyft , but I kept getting an 'Access-Control-Allow-Origin' error.

    After some research I found this post which said that a work-around is done in node_helper.js and referenced this module.

    So, I have tried my hand at an Uber module done in that fashion, but no luck. I have put a bunch of Log.log() statements in my code but I am not seeing anything in the console to help me debug. The mirror shows the statement “Checking Uber status…”

    Here’s the module code:

    /* global Module */
    
    /* Magic Mirror
     * Module: Uber
     * 
     * based on MagicMirror work by Michael Teeuw http://michaelteeuw.nl
     * MIT Licensed.
     */
    
    Module.register("MMM-uber",{
    
    	// Default module config.
    	defaults: {
    		lat: null,
    		lng: null,
    		product_id: null,
    		client_id: null,
    		uberServerToken: null,
    
    		updateInterval: 5 * 60 * 1000, // every 5 minutes
    		animationSpeed: 1000,
    	},
    
    	// Define required scripts.
    	getScripts: function() {
    		return ["moment.js", "https://code.jquery.com/jquery-2.2.3.min.js"];
    	},
    
    	// Define required styles.
    	getStyles: function() {
    		return ["MMM-uber.css"];
    	},
    
    	start: function() {
    		Log.info("Starting module: " + this.name);
    
    		// Set locale.
    		moment.locale(config.language);
    
    		// variables that will be loaded from service
    		this.uberTime = null;
    		this.uberSurge = null;
    
    		this.loaded = false;
    		this.sendSocketNotification('CONFIG', this.config);
    	},
    
    	// unload the results from uber services
    	processUber: function(FLAG, result) {
    		var self = this;
    		Log.log("ProcessUber");
    
    		// go through the time data to find the uberX product
    		if (FLAG === "TIME"){
    			Log.log("Time");
    			Log.log(result);
    			for (var i = 0, count = result.times.length; i < count ; i++) {
    
    				var rtime = result.times[i];
    				
    				if(rtime.display_name === "uberX"){
    					// convert estimated seconds to minutes
    					this.uberTime = rtime.estimate / 60;
    					break;
    				}
    			}
    		}
    
    		// go through the price data to find the uberX product
    		else if (FLAG === "PRICE"){
    			Log.log("Price");
    			Log.log(result);
    			for( var i=0, count = result.prices.length; i< count; i++) {
    				var rprice = result.prices[i];
    
    				if(rprice.display_name === "uberX"){
    					// grab the surge pricing
    					this.uberSurge = rprice.surge_multiplier;
    					break;
    				}
    			}
    		}
    	},
    
    	// Override dom generator.
    	getDom: function() {
    		var wrapper = document.createElement("div");
    
    		var uber = document.createElement("div");
    		uber.className = "uberButton";
    		
    		var uberIcon = document.createElement("img");
    		uberIcon.className = "badge";
    		uberIcon.src = "modules/MMM-uber/UBER_API_Badges_1x_22px.png";
    
    		var uberText = document.createElement("span");
    
    		if(this.loaded) {
    			var myText = "UberX in "+ this.uberTime +" min ";
    			Log.log("ubersurge: " + this.uberSurge);
    			// only show the surge pricing if it is above 1.0
    			if(typeof this.uberSurge !== "undefined" && this.uberSurge > 1.0){
    				myText += " - " + this.uberSurge + "X surge pricing";
    			}
    			uberText.innerHTML = myText;
    		} else {
    			// Loading message
    			uberText.innerHTML = "Checking Uber status ...";
    		}
    
    		uber.appendChild(uberIcon);
    		uber.appendChild(uberText);
    		
    		wrapper.appendChild(uber);
    		return wrapper;
    	},
    
    	socketNotificationReceived: function(notification, payload) {
    		Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
    		if (notification === "TIME") {
    			this.processUber("TIME", payload);
    			this.updateDom(this.config.animationSpeed)
    		}
    		else if (notification === "PRICE") {
    			this.processUber("PRICE", payload);
    			this.loaded = true;
    			this.updateDom(this.config.animationSpeed);
    		}
    	}
    
    });
    
    

    And the code in node_helper.js

    'use strict';
    
    /* Magic Mirror
     * Module: MMM-lyft
     *
     * By Kyle Kelly
     * MIT Licensed.
     */
    
    const NodeHelper = require('node_helper');
    var request = require('request');
    var moment = require('moment');
    
    module.exports = NodeHelper.create({
    
    	start: function() {
    		var self = this;
    		console.log("Starting node helper for: " + this.name);
    
    		this.started = false;
    		this.config = null;
    	},
    
    	getData: function() {
    		var self = this;
    						
    		request({
    			url: "https://api.uber.com/v1/estimates/time",
    			method: 'GET',
    			headers: {
    		        "Authorization": "Token " + self.config.uberServerToken
    		    },
    		    data: {
    		        start_latitude: self.config.lat,
    		        start_longitude: self.config.lng,
    		        product_id: self.product_id
    		    },
    		}, function (error, response, body) {
    			
    			if (!error && response.statusCode == 200) {
    				self.sendSocketNotification("TIME", body);
    			}
    		});
    
    		request({
    			url: "https://api.uber.com/v1/estimates/price",
    			method: 'GET',
    			headers: {
    				        "Authorization": "Token " + self.config.uberServerToken
    		    },
    		    data: {
    		        start_latitude: self.config.lat,
    		        start_longitude: self.config.lng,
    
    		        end_latitude: self.config.lat,
    		        end_longitude: self.config.lng
    		    },
    		}, function (error, response, body) {
    			
    			if (!error && response.statusCode == 200) {
    				self.sendSocketNotification("PRICE", body);
    			}
    		});
    
    		setTimeout(function() { self.getData(); }, this.config.updateInterval);
    	},
    
    	socketNotificationReceived: function(notification, payload) {
    		var self = this;
    		if (notification === 'CONFIG' && self.started == false) {
    			self.config = payload;
    			self.getData();
    			self.started = true;
    		}
    	}
    });
    
    

    Any help would be appreciated. Thanks!



  • @kal are you looking at the correct console? Log.log logs to electron console, which is visible when starting MM with npm start dev (or by pressing some shortcut which I forgot; search the forum if you want to know). The terminal where you start MM is kind of useless for debugging :(



  • @Anhalter42 said in CORS using node_helper.js for Uber and Lyft APIs:

    (or by pressing some shortcut which I forgot; search the forum if you want to know).

    Try F12.



  • As an example ONLY!

       getStuff: function(url) {
      request({
            url: "https://www.whereever.com/stuff.json",
            method: 'GET',
            headers: {
                'User-Agent': 'MagicMirror/1.0 '
            }
      }, (error, response, body) => {
            if (!error && response.statusCode == 200) {
       blah..blah....blah.......


  • @Anhalter42 I’m looking at the JavaScript console. The IP of my laptop is whitelisted, so I go to https://IP.of.Raspberry.Pi:8080 in Chrome and then go to View>Developer>JavaScript Console.

    Is there another way I can get statements to print to that console ?



  • @cowboysdude isn’t that what I am doing? Can you explain how your solution differs from mine?



  • When you request a webpage, your browser sends a number of headers to the server hosting the site that you’re visiting.

    These headers occur during a negotiation process that helps the browser and the hosting server determine the best way to provide the requested information. The user-agent header identifies the application requesting the information from the server, typically a browser. This identification string is called the user-agent string and contains tokens that provide specific details about the program making the request.



  • @cowboysdude I don’t think the user-agent string is required when making an HTTP request. According to the Uber API docs it doesn’t look like I need one.



  • @kal well then… I know its not helping, but it should work as you described. Not seeing anything in js console is a serious problem when developing. Did you try other browsers? If nothing appears in any browser AND on raspberry itself (with npm start dev), then something is seriously wrong…



  • I was able to fix this. See below for the module code

    /* global Module */
    
    /* Magic Mirror
     * Module: Uber
     * 
     * Shows the time and surge pricing for UberX
     *
     * By Kyle Kelly
     * based on MagicMirror work by Michael Teeuw http://michaelteeuw.nl
     * and by derickson https://github.com/derickson/MMderickson/tree/master/uber
     * MIT Licensed.
     */
    
    Module.register("MMM-uber",{
    
    	// Default module config.
    	defaults: {
    		lat: null,
    		lng: null,
    		ride_type: "uberX",
    		uberServerToken: null,
    
    		updateInterval: 5 * 60 * 1000, // every 5 minutes
    		animationSpeed: 1000,
    	},
    
    	// Define required scripts.
    	getScripts: function() {
    		return ["moment.js", "https://code.jquery.com/jquery-2.2.3.min.js"];
    	},
    
    	// Define required styles.
    	getStyles: function() {
    		return ["MMM-uber.css"];
    	},
    
    	start: function() {
    		Log.info("Starting module: " + this.name);
    
    		// Set locale.
    		moment.locale(config.language);
    
    		// variables that will be loaded from service
    		this.uberTime = null;
    		this.uberSurge = null;
    
    		this.loaded = false;
    		Log.log("Sending CONFIG to node_helper.js in " + this.name);
    		Log.log("Payload: " + this.config)
    		this.sendSocketNotification('CONFIG', this.config);
    	},
    
    	// unload the results from uber services
    	processUber: function(FLAG, result) {
    		var self = this;
    		Log.log("ProcessUber");
    
    		// go through the time data to find the uberX product
    		if (FLAG === "TIME"){
    			Log.log("Time:");
    			Log.log(result);
    			for (var i = 0, count = result.times.length; i < count ; i++) {
    
    				var rtime = result.times[i];
    				
    				if(rtime.display_name === this.config.ride_type){
    					// convert estimated seconds to minutes
    					this.uberTime = rtime.estimate / 60;
    					break;
    				}
    			}
    		}
    
    		// go through the price data to find the uberX product
    		else if (FLAG === "PRICE"){
    			Log.log("Price:");
    			Log.log(result);
    			for( var i=0, count = result.prices.length; i< count; i++) {
    				var rprice = result.prices[i];
    
    				if(rprice.display_name === this.config.ride_type){
    					// grab the surge pricing
    					this.uberSurge = rprice.surge_multiplier;
    					break;
    				}
    			}
    		}
    	},
    
    	// Override dom generator.
    	getDom: function() {
    		var wrapper = document.createElement("div");
    
    		var uber = document.createElement("div");
    		uber.className = "uberButton";
    		
    		var uberIcon = document.createElement("img");
    		uberIcon.className = "badge";
    		uberIcon.src = "modules/MMM-uber/UBER_API_Badges_1x_22px.png";
    
    		var uberText = document.createElement("span");
    
    		if(this.loaded) {
    			var myText = this.config.ride_type + " in "+ this.uberTime +" min ";
    			Log.log("ubersurge: " + this.uberSurge);
    			// only show the surge pricing if it is above 1.0
    			if(typeof this.uberSurge !== "undefined" && this.uberSurge > 1.0){
    				myText += " - " + this.uberSurge + "X surge pricing";
    			}
    			uberText.innerHTML = myText;
    		} else {
    			// Loading message
    			uberText.innerHTML = "Checking Uber status ...";
    		}
    
    		uber.appendChild(uberIcon);
    		uber.appendChild(uberText);
    		
    		wrapper.appendChild(uber);
    		return wrapper;
    	},
    
    	socketNotificationReceived: function(notification, payload) {
    		Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
    		if (notification === "TIME") {
    			this.processUber("TIME", JSON.parse(payload));
    			this.updateDom(this.config.animationSpeed)
    		}
    		else if (notification === "PRICE") {
    			this.processUber("PRICE", JSON.parse(payload));
    			this.loaded = true;
    			this.updateDom(this.config.animationSpeed);
    		}
    	}
    
    });
    
    

    and the node_helper.js code

    'use strict';
    
    /* Magic Mirror
     * Module: MMM-uber
     *
     * By Kyle Kelly
     * MIT Licensed.
     */
    
    const NodeHelper = require('node_helper');
    var request = require('request');
    var moment = require('moment');
    
    module.exports = NodeHelper.create({
    
    	start: function() {
    		var self = this;
    		console.log("Starting node helper for: " + this.name);
    
    		this.config = null;
    	},
    
    	getData: function() {
    		var self = this;
    
    		this.sendSocketNotification("Test", 2);
    		this.sendSocketNotification("LATITUDE", this.config.lat);
    		this.sendSocketNotification("LONGITUDE", this.config.lng);
    						
    		
    		request({
    			url: "https://api.uber.com/v1/estimates/time?start_latitude=" + this.config.lat + "&start_longitude=" + this.config.lng,
    			method: 'GET',
    			headers: {
    		        'Authorization': 'Token ' + this.config.uberServerToken,
    		        'Accept-Language': 'en_US',
    		        'Content-Type': 'application/json'
    		    },
    		}, function (error, response, body) {
    			
    			if (!error && response.statusCode == 200) {
    				self.sendSocketNotification("TIME", body);
    			}
    			else {
    				self.sendSocketNotification("ERROR", "In TIME request with status code: " + response.statusCode);
    			}
    		});
    
    		request({
    			url: "https://api.uber.com/v1/estimates/price?start_latitude=" + this.config.lat + "&start_longitude=" + this.config.lng + "&end_latitude=" + this.config.lat + "&end_longitude=" + this.config.lng,
    			method: 'GET',
    			headers: {
    				'Authorization': 'Token ' + this.config.uberServerToken,
    		        'Accept-Language': 'en_US',
    		        'Content-Type': 'application/json'
    		    },
    		}, function (error, response, body) {
    			
    			if (!error && response.statusCode == 200) {
    				self.sendSocketNotification("PRICE", body);
    			}
    			else {
    				self.sendSocketNotification("ERROR", "In PRICE request with status code: " + response.statusCode);
    			}
    		});
    
    		setTimeout(function() { self.getData(); }, this.config.updateInterval);
    		
    	},
    
    	socketNotificationReceived: function(notification, payload) {
    		//var self = this;
    		this.sendSocketNotification("Test", 0);
    		if (notification === 'CONFIG') {
    			this.sendSocketNotification("Test", 1);
    			this.config = payload;
    			this.getData();
    		}
    	}
    });
    
    

Log in to reply
 

Looks like your connection to MagicMirror Forum was lost, please wait while we try to reconnect.