About

This is a simple interface to the Twitter API written by Ian Eslick. It also implements the Search API and provides a tinyurl mapping API and the REPL interface performs automatic conversions to tiny urls. The library is currently only available via darcs.

darcs get http://www.common-lisp.net/project/cl-twitter/darcs/cl-twitter

I will be putting a tarball up on cliki for asdf-install after it's had some more exercise. There are at least two other libraries out there that came out literally on the same day as I posted this to cl.net. 'cl-twit' by Chaitanya Gupta and 'cl-twitter' by Chris Davies. With permission of the author, I reproduced most of the cl-twit REPL API in the latest patch as well as used his tinyurl function.

Loading cl-twitter

cl-twitter depends on: cl-json, drakma, trivial-http, anaphora and cl-ppcre

(asdf:oos 'asdf:load-op :cl-twitter) -> Creates package :twitter

API for the REPL

Authentication

Most API commands require an authenticating user. An authenticating user (with valid username & password slots) can be passed to a command using the :user option. There is a convenience function authenticate-user which takes a username and password, creates and populates a user object (if authentication works) and sets a global variable *twitter-user* which will be used to authenticate calls by default. The :user option overrides the default parameter.

User-level REPL API

There is a nice set of interactive routines for use at the REPL. Each command prints the return values directly, then returns a set of internal objects represneting the full details of each reply. You can use 'describe' on any element to see key fields.

(public-timeline)            ;; public timeline

;; User specific commands
(authenticate-user screen-name password) ;; will set the default user if valid
(timeline)            ;; timeline for current authenticated user or use :id keyword argument
(friends-timeline)    ;; full timeline including friends tweets
(send-tweet text)     ;; will post a tweet / status update for the current user
(update text)         ;; alias for send-tweet

;; Replies
(reply-to tweet text) ;; Send a reply
(@reply-to tweet text) ;; Send a reply, but prepend @username to text

;; Messages
(messages)            ;; Your messages
(send-message user message) ;; Send a message
(sent-messages)       ;; Messages you've sent

Example run:

TWITTER> (authenticate-user "username" "password")
#<TWITTER-USER 'ieslick'>

TWITTER> (user-timeline)
status: "The lisp twitter api is nearly done!"
by: First Last (username) on: Tue Feb 17 00:49:11 +0000 2009

status: "Benefits of working from home; lunchtime stew in Cambridge, MA http://loopt.us/-Hps2Q"
by: First Last (username) on: Mon Feb 16 17:49:52 +0000 2009

status: "My lisp can tweet!"
by: First Last (username) on: Mon Feb 16 04:52:28 +0000 2009

status: "Family outing! in Cambridge, MA http://loopt.us/zUhMpQ"
by: First Last (username) on: Sun Feb 15 21:14:26 +0000 2009

(#<TWEET 'username' id:1219635898> #<TWEET 'username' id:1217269236>
 #<TWEET 'username' id:1215984895> #<TWEET 'username' id:1214353382>)

TWITTER> (print-tweets *)
status: "The lisp twitter api is nearly done!"
by: First Last (username) on: Tue Feb 17 00:49:11 +0000 2009

status: "Benefits of working from home; lunchtime stew in Cambridge, MA http://loopt.us/-Hps2Q"
by: First Last (username) on: Mon Feb 16 17:49:52 +0000 2009

status: "My lisp can tweet!"
by: First Last (username) on: Mon Feb 16 04:52:28 +0000 2009

status: "Family outing! in Cambridge, MA http://loopt.us/zUhMpQ"
by: First Last (username) on: Sun Feb 15 21:14:26 +0000 2009

TWITTER> (send-tweet "cl-twitter is released!")
#<TWEET 'username' id:1219635898>

TWITTER> (describe *)
by: usernam (First Last) created: Tue Feb 17 17:33:33 +0000 2009
msg: cl-twitter is released!
; No value

Search API

The search API returns a 'search-result element which contains a set of 'search-ref elements accessible via (search-result-results elt)
(do-search "query string" &rest args) ;; is a shortcut for
   (twitter-op :search :q "query string" &rest args)
   ;; and returns two values: the list of refs and the 'search-result elt.

(twitter-trends)  ;; returns the top 20 twitter search trends

;; Can also directly do tinyurl conversions
(get-tinyurl "url")
Example use:
TWITTER> (twitter-search "#lisp")
(#<TWITTER-SEARCH-REF 'kotrit'> #<TWITTER-SEARCH-REF 'gibsonf1'>
 #<TWITTER-SEARCH-REF 'dhess'> #<TWITTER-SEARCH-REF 'baphled'>
 #<TWITTER-SEARCH-REF 'TheSeth26'> #<TWITTER-SEARCH-REF 'cdeger'>
 #<TWITTER-SEARCH-REF 'taphon'> #<TWITTER-SEARCH-REF 'dhess'>
 #<TWITTER-SEARCH-REF 'dhess'> #<TWITTER-SEARCH-REF 'yonkeltron'>
 #<TWITTER-SEARCH-REF 'steveportigal'> #<TWITTER-SEARCH-REF 'duck1123'>
 #<TWITTER-SEARCH-REF 'edgargoncalves'> #<TWITTER-SEARCH-REF 'edgargoncalves'>
 #<TWITTER-SEARCH-REF 'adam_houston'>)
#<TWITTER-SEARCH '%23lisp'>
TWITTER> (mapcar #'search-ref-text *)
 ("Luckily Slime takes care of most of the formatting quite nicely - RT @dhess Riastradh's Lisp style rules #lisp http://tinyurl.com/2onk5x"
 "Riastradh's Lisp style rules #lisp http://tinyurl.com/2onk5x"
 "I really need to learn #LISP one day" "Why macros over functions?? #lisp"
 "Ich will Clojure fr .NET! Dynamisch, funktional, STM eingebaut, schnell: http://bit.ly/4qX28T #lisp #jvm"
 "What's a good ide for #Lisp, any good books on the language written recently?"
 "Technical issues re: Lisp-1 vs. Lisp-2 #pl #lisp http://tinyurl.com/2kh96k"
 "What Common Lisp conditions (exceptions) are really about #lisp http://tinyurl.com/8r5yeh"
 "@theseth26 the folks in #emacs on freenode are often less snippy than the folks on #lisp. i lurk there, will talk. hack strong and prosper!"
 "@joshdamon I'm tempted to call it twethival #lisp"
 "@horseman !stumpwm is the window manager for #emacs and #screen users. It's all keyboard commands, and written in common #lisp"
 "Drawing a tree graph of my objects and their slots, in #lisp. looking for the easier way to do it. feel free to drop tips and hints."
 "Finished a functional webapp server with offline work support. Serialized proxies fly over http between two #lisp servers, works well."
 "Too bad we are moving to an integrated system though. Really wanted to rewrite the whole thing in #Lisp one of these days. Or maybe #Python.")

Error Handling

Any API call errors throw a twitter-api-condition which provides the return code and short and long code messages. It also provides the failing URI and the specific server message. The accessors are not exported to avoid conflicts, but the slotnames are:
   return-code, short, long, request, uri.

You can play with this, for example, by trying to perform an API command with invalid user authentication. For debugging purposes the API keeps the last condition in twitter::*last-condition*.

Low Level, Programmatic Interface and Objects

The generic, low-level interface to the API is via the twitter-op function:

   (twitter-op :command &rest args)

This top level function sends an API call for :command with any arguments to the twitter server and returns one or more 'elements' (see types below). This API uses struct objects to encapsulate composite values such as users or tweets. I tried to be smart about converting between names such as 'user_id' and the more natural :user-id parameter names on the lisp side.


TWITTER> (twitter-op :user-show :id "lisp4life")
#<TWITTER-USER 'lisp4life'>

TWITTER> (describe *)
Name: Lisp ('lisp4life') id:19387004
Created at: Fri Jan 23 08:47:36 +0000 2009
Description: "I'm the Greatest Gay Rapper in the World!"
Counts: friends 2, followers 0, statuses 1
Location: West Hollywood, CA
Time Zone: Alaska

TWITTER> (twitter-op :friend-create :id "twitterapi" :follow t)
#<TWITTER_USER 'twitterapi'

You can view documentation for commands and elements using:

(command-help [command-name]) ;; prints a summary of all commands or command-name
(element-help 'type)
valid types: twitter-user, tweet, twitter-message, search-result, search-ref

Mailing Lists

API Status

This interface was interactively tested, but bugs remain and not all features have been exercised. Help tracking down the last of the bugs is always appreciated!

I have also not completely documented all the element slots. This should be easy to fix and you can also refer to the twitter APIs.

TODO:

Back to Common-lisp.net.

Valid XHTML 1.0 Strict