Monday, August 15, 2016

Fun project for talk like a pirate day - a Pirate Slack bot!

(image source - wikipedia.com)

It's almost Internation Talk Like a Pirate day.  If you can believe that such a day exists...

In mid May some friends, Charley, Evan, another new fellow that we met named Josh, and I were at OSCON in Austin.  We participated in a hackathon one day there.

We only had one afternoon to write all of the code.  We utilized an existing npm / node.js package for a head start on the Slack bot.  Here is the Slackbot code - https://github.com/evansong/PirateBotKit .  It allows a user to type in "pirate hello" for example and the bot will output "ahoy".  https://github.com/evansong/PirateBotKit/blob/master/slack_pirate_bot.js has the majority of the Slack bot code.  You can check out the keys and values that we loaded into Redis here - https://github.com/evansong/PirateBotKit/blob/master/dictionary.js .

For the server side, Evan wanted to use Microsoft's WebAPI 2 REST APIs hosted in Azure along with Redis.  Here is the relatively simple REST API endpoints - https://github.com/evansong/PirateApi/blob/master/PirateApi/Controllers/PirateController.cs .

In the end, it was a fun experience to throw an application together in an afternoon.  The creator of Botkit was there and even checked out our app.

If you haven't participated in a hackathon yet I highly recommend it.  It's a great way to work on fun and interesting projects, meet new people, and work with new technologies.  Also, they are great for team building as well if you'd like to organize one for you and your colleagues.

Cheers.

Tuesday, April 26, 2016

Simple node.js app using YQL and Mailgun

YQL is a great and very responsive service for fetching JSON data.

Here's a simple example query.  The test button allows you to get a sample of the results and get a REST URL.

Here is some example code for fetching some ticker data.

// Get query results from Yahoo's YQL service
var request = require('request');
var fs = require('fs');

// # INSERT YOUR URLs HERE
var urls = [...];

// formatAsHtml - helper for formatting strings as simple HTML
var formatAsHtml = function (inputString, htmlTag) {
    switch (htmlTag) {
        case "b":
            formattedResult = "<b>" + inputString + "</b>";
            break;
        case "i":
            formattedResult = "<i>" + inputString + "</i>";
            break;
        case "h1":
            formattedResult = "<h1>" + inputString + "</h1>";
            break;
        case "h2":
            formattedResult = "<h2>" + inputString + "</h2>";
            break;
        case "h3":
            formattedResult = "<h3>" + inputString + "</h3>";
            break;
        case "hr":
            formattedResult = inputString + "<hr/>";
            break;
    }
    formattedResult += "<br/>";
 
    return formattedResult;
}

// logOrganizedResults - prep results for html file
var logOrganizedResults =  function (error, response, body) {
    if (!error && response.statusCode === 200) {
        console.log(formatAsHtml("Symbol " + response.body.query.results.quote.symbol,"b"));
        console.log("Name " + response.body.query.results.quote.Name);
        console.log(formatAsHtml("LastTradeWithTime " + response.body.query.results.quote.LastTradeWithTime, "i"));
        console.log(formatAsHtml("Change_PercentChange " + response.body.query.results.quote.Change_PercentChange,"b"));
        console.log("Volume " + response.body.query.results.quote.Volume);
        console.log("YearRange " + response.body.query.results.quote.YearRange);
        console.log("PercebtChangeFromYearHigh " + response.body.query.results.quote.PercebtChangeFromYearHigh);
        console.log("DaysHigh " + response.body.query.results.quote.DaysHigh);
        console.log("DaysLow " + response.body.query.results.quote.DaysLow);
        console.log(formatAsHtml("\r\n","hr"));
    } else {
        console.error(error);
    }
};

// Request data from Yahoo's YQL service
for (var i = 0; i < urls.length; i++) {
    request({url: urls[i], json: true}, logOrganizedResults);
}

You can name this node.js file as app.js or whatever you choose and run it as "node app.js > results.html" on Windows (*nix should be similar).

To send an email of the results you can do the following with the Mailgun API.

var Mailgun = require('mailgun-js');
var api_key = 'YOURKEYGOESHERE';
var domain = 'YOURDOMAINGOESHERE';
var from_who = 'YOURFROMEMAILGOESHERE';

var path = require("path");
var fp = [path.join(__dirname, 'results.html')];
var data = {
    from: from_who,
    to: "RECIPIENTGOESHERE",
    subject: 'SUBJECTGOESHERE',
    text: 'Your query results are attached.',
    attachment: fp
};

// submitEmailWithAttachment - sends email with attachment(s)
var submitEmailWithAttachment = function() {
    var mailgun = new Mailgun({apiKey: api_key, domain: domain});

    mailgun.messages().send(data, function (error, body) {
        if (error) {
            console.log('error', {error: error});
        }
        else {
            console.log("attachment sent", fp);
        }
    });
};

// Send email with the query results
submitEmailWithAttachment();

Then to put it all together, you can run it with a batch file (contents below), or a shell script on *nix.

del *.html
node app.js > results.html
node sendEmail.js

Alternatively, you could use the async npm module or some other flow control module.  Then you could host the node app in AWS Lamba, Azure, etc...  You could also improve the code a bit by refactoring and adding unit tests with Chai, or something similar.  Cheers.

P.S. The source is now on Github - https://github.com/kristianjaeger/StockDataEmailer .