As a disclaimer I'm fairly new to both javascript and Azure. My goal is to build a Tableau web data connector. I have the following scripts.
<html>
<head>
<title>Facebook Likes</title>
<meta http-equiv="Cache-Control" content="no-store" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<script src="https://connectors.tableau.com/libs/tableauwdc-2.3.latest.js" type="text/javascript"></script>
<script src="FacebookLikes.js" type="text/javascript"></script>
</head>
<body>
<div class="container container-table">
<div class="row vertical-center-row">
<div class="text-center col-md-4 col-md-offset-4">
<button type = "button" id = "submitButton" class = "btn btn-success" style = "margin: 10px;">Get Facebook Likes!</button>
</div>
</div>
</div>
</body>
</html>
and
var http = require('http');
http.createServer((function() {
// Create the connector object
var myConnector = tableau.makeConnector();
// Define the schema
myConnector.getSchema = function(schemaCallback) {
var cols = [{
id: "id",
dataType: tableau.dataTypeEnum.int
}, {
id: "link",
dataType: tableau.dataTypeEnum.string
}, {
id: "likes",
dataType: tableau.dataTypeEnum.int
}];
var tableSchema = {
id: "Facebook",
alias: "real-time likes",
columns: cols
};
schemaCallback([tableSchema]);
};
// Download the data
myConnector.getData = function(table, doneCallback) {
var username = 'xxx';
var password = 'xxx';
var url = 'xxxx';
var xhttp = new XMLHttpRequest();
xhttp.open('POST', url, true);
xhttp.onreadystatechange = function() {//Call a function when the state changes.
if(xhttp.readyState == 4 && xhttp.status == 200) {
var response = JSON.parse(xhttp.responseText)
tableData = [];
tableData.push({
"id": response.id,
"link": response.link,
"likes": response.likes,
});
table.appendRows(tableData);
doneCallback();
}
}
params = username + ';' + password
xhttp.send(params)
};
tableau.registerConnector(myConnector);
// Create event listeners for when the user submits the form
$(document).ready(function() {
$("#submitButton").click(function() {
tableau.connectionName = "Facebook Likes"; // This will be the data source name in Tableau
tableau.submit(); // This sends the connector object to Tableau
});
});
})).listen(process.env.PORT || 1337);
I built and tested the html and javascript locally, and everything works as expected. The only thing that I have added from my dev version is the createServer call. If I do a git push according to Azure documentation the push executes successfully, and I can see the deployment listed in my app under "Deployment Options"; however, when I open the webpage I get the message, "you do not have permission to view this directory or page." My research lead me to include package.json and web.config files as follows.
{
"name": "azure-facebook-likes",
"author": "Xander",
"version": "1.0",
"description": "application for use with Tableau web data connector to return facebook likes",
"tags": [
"facebook",
"tableau"
],
"license": "MIT",
"scripts": {
"start": "node FacebookLikes.js"
}
}
--
<configuration>
<system.webServer>
<handlers>
<!-- indicates that the app.js file is a node.js application to be handled by the iisnode module -->
<add name="iisnode" path="FacebookLikes.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<!-- Don't interfere with requests for logs -->
<rule name="LogFile" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^[a-zA-Z0-9_\-]+\.js\.logs\/\d+\.txt$" />
</rule>
<!-- Don't interfere with requests for node-inspector debugging -->
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^FacebookLikes.js\/debug[\/]?" />
</rule>
<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}" />
</rule>
<!-- All other URLs are mapped to the Node.js application entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True" />
</conditions>
<action type="Rewrite" url="FacebookLikes.js" />
</rule>
</rules>
</rewrite>
</system.webServer>
<security>
<ipSecurity allowUnlisted="true">
</security>
</configuration>
With this configuration, when I browse to the web page I get the message, "The page cannot be displayed because an internal server error has occurred." Logging-errors.txt reveals the following, "Application has thrown an uncaught exception and is terminated: ReferenceError: tableau is not defined." The tableau definition comes from the connectors.tableau.com dependency in the html file, but from what I can tell, when I specify
"scripts": {
"start": "node FacebookLikes.js"
}
in the package.json file the scripts in the html file aren't loading. I have been working on this for a couple days and am bereft of ideas. Does anyone have a suggestion on how to get the dependencies to load? Or can someone push me in the right direction as to what I should be looking at? Any insight would be greatly appreciated.
Thanks!