0

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!

2 Answers 2

1

The code you are using should run from the browser rather than from Node.js. You could move the code from FacebookLikes.js to the HTML file like this:

<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>

    <script>
        $(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
            });
        });
    </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>

<script>

    var myConnector = tableau.makeConnector();

    // Define the schema
    myConnector.getSchema = function(schemaCallback) {
        // ...
    };

    // Download the data
    myConnector.getData = function(table, doneCallback) {
        // ...
    };

    tableau.registerConnector(myConnector);

</script>

</html>

And then delete FacebookLikes.js, web.config and package.json files as well.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the suggestion! I tried it, but I received the "...do not have permission..." message again. The ErrorPage.htm log reveals "HTTP Error 403.14 - Forbidden. The Web server is configured to not list the contents of this directory. Most likely causes: A default document is not configured for the requested URL, and directory browsing is not enabled on the server." I'm not sure how to configure a default document in an Azure environment. This seemed like a great idea that I hadn't thought of. Is there anything else I can try?
0

Azure has a list of default documents under application settings. I had named my html file FacebookLikes.html, which is (unsurprisingly) not a default document name. I renamed my file index.html, deleted the web.config and package.json files, and removed the create server call from the javascript code (and added a trailing ()), and the web application functions as expected. Conceivably I could add FacebookLikes.html to the default documents, and it should work.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.