Tweeting from Clojure

Posted by Ray Miller on Sat 29 June 2013
Tweeting from Clojure

I'm working on a small Clojure application that will update my Twitter status whenever I post a new article to this blog. Services like twitterfeed.com already provide this functionality, but I thought it would be instructive to develop my own solution. After a little research, the tweeting component turns out to be very straightforward to implement.

A quick Google search turns up the twitter-api library. This appears to be very full-featured and quite easy to use, but does a lot more than we need. Under the covers it uses clj-ouath for OAuth support, and it turns out the author of clj-oauth has also written a Twitter library, clojure-twitter, but that hasn't been updated in over a year.

A Clojars search finds another OAuth library, oauth-clj, and buried away in here is a very nice Twitter client. This library has been updated more recently than any of the others, the API it presents is simple, and the underlying code is easy to understand and (I think) nicely designed. This looks like a good choice for our simple use-case. So add to your project's dependencies:

[oauth-clj "0.1.4"]

Before we start coding, we need to get some credentials for the Twitter API. Our application only needs to send tweets on behalf of a single user, so we can follow the instructions in the Tokens from dev.twitter.com section. (You might find this post helpful if you don't want to use your main Twitter account for testing.) Once you've completed the Create my access token step, you'll have a Consumer key, Consumer secret, Access token, and Access token secret. The secrets should not be disclosed to anyone, so we'll store them in a properties file that only we can read, resources/twitter.properties:

consumer-key=CONSUMER_KEY
consumer-secret=CONSUMER_SECRET
access-token=ACCESS_TOKEN
access-token-secret=ACCESS_TOKEN_SECRET

We need to parse the properties file to make the credentials available to our application. The following function uses java.util.Properties to read the properties from a file, then (for convenience) transforms the keys to Clojure keywords, and returns the properties as a map:

(require '[clojure.java.io :as io])

(defn read-properties
  "Parse a properties file, convert the property keys to Clojure
  keywords and return as a Clojure map."
  [resource-name]
  (when-let [resource (io/resource resource-name)]
    (let [properties (java.util.Properties.)]
      (with-open [stream (io/input-stream resource)]
        (.load properties stream))
      (zipmap (map keyword (keys properties))
              (vals properties)))))

Now we can create our twitter client:

(require '[oauth.twitter :refer [oauth-client]])

(defn client
  "Create an OAuth client for the Twitter API, using the supplied `credentials`."
  [credentials]
  (ouath-client (:consumer-key credentials)
                (:consumer-secret credentials)
                (:access-token credentials)
                (:access-token-secret credentials)))

Finally, we can send our first tweet:

(defn tweet
  "Tweet a status update."
  [twitter-client status]
  (twitter-client {:method      :post
                   :url         "https://api.twitter.com/1.1/statuses/update.json"
                   :form-params {:status status}}))

;; Read Twitter credentials from a properties file
(def credentials (read-properties "twitter.properties"))

;; Create a Twitter client with the specified credentials
(def twitter-client (client credentials))

;; Send our first tweet!
(tweet twitter-client "My first tweet")

Thanks to the excellent libraries at our disposal, sending tweets from a Clojure program is extremely easy - ignoring the boilerplate to read properties, it's fewer than 20 lines of code.

The source code from this article is available as a gist.

About

This is the personal web site of Ray Miller, a software developer and one-time mathematician living in Cambridge, UK.