I have this tiny app on an Ec2 micro instance. It uses the Twitter API, via the Twitter4J Java client library, to record the number of followers for a given list of Twitter handles. I’ve cronned it to run once a day, so for each of the Twitter accounts I’m interested in, for example my bots, I have a CSV file that tracks the number of followers over time. Simple, crude, and good enough.
A friend asked me if I would do the same for his Twitter account. “No problem”, I said, because, you know, I’m generous like that. Add it to the list, CSV file magically appears the next day, and Bob’s yer uncle. Every once in a while I would email him an up-to-date copy of that file, that analytical masterpiece, that source of valuable “Business Information”, and he’d plot it as a graph in Excel, or whatever it is he does with it.
This arrangement was fine for a couple of weeks, but it soon became clear it would be better for both of us if he had direct access to his data so we could do away with this bothersome emailing business altogether. So, how to do that? Call me skittish, but I’m not mad keen on granting SSH access to any old Tom, Dick or Harry, personal friend or no. And in any case, I’m sure he’d find SCP a little bit of a faff. How about good old HTTP?
That seemed like a good idea, but I didn’t want to install a full-featured web server like Apache. In the past I’ve played with Sinatra, the lightweight Ruby web app framework, and it’s ideal for such a trivial use case. I wondered if I could find a similar microframework written in Python, and it turns out there are several. I decided to give Flask a whirl. A brief gander at the quick start guide later, I was ready to start Flasking:
import sys, os from flask import Flask, make_response, abort app = Flask(__name__) stats_dir = '.' @app.route('/twitstats/') def show_stats(user): stats_file = stats_dir + "/" + user + "-followers.csv" if os.path.isfile(stats_file) == False: abort(404) response = make_response( open(stats_file, "r").read() ) response.headers['Content-type'] = 'text/csv' return response if __name__ == '__main__': if len(sys.argv) > 1: stats_dir = sys.argv[1] app.run(host='0.0.0.0')
Exactly as I had hoped, I got the job done with little trouble and in just a few short lines. Now all my follower tracking CSV files are available over the web; hitting this minimal HTTP interface from the client side looks like:
curl -v http://myinstance.amazonaws.com:5000/twitstats/KevKeeganQuotes > GET /twitstats/KevKeeganQuotes HTTP/1.1 > User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3 > Host: myinstance.amazonaws.com:5000 > Accept: */* < HTTP/1.0 200 OK < Content-type: text/csv < Content-Length: 3751 < Server: Werkzeug/0.8.3 Python/2.6.5 < Date: Mon, 15 Jul 2013 02:24:15 GMT 12-01-2013 03:50:03, 911 13-01-2013 03:50:02, 913 14-01-2013 03:50:03, 917 ...
For hacking out something tiny, in this case an HTTP resource that will be (barely) used by literally two people, microframeworks like Flask are great fun to play with. Now, that’s not to say you can’t use them to build serious apps. Flask supports WSGI, has a templating system, decent documentation, good support for logging, security and sessions, is compatible with platforms like Heroku and App Engine, and is extensible in all kinds of ways, for example if you want ORM. All good, grown-up stuff. But the speed with which it allows you to wrap an HTTP resource or two round something trivial is pretty impressive.
Leave a Reply