Delicious client v1.0

Dave Gurnell and Noel Welsh ({dave, noel} at untyped)

1 Introduction

This library provides structures and procedures for accessing the HTTP API of the social bookmarking service. The library handles all connection, encryption and authentication with, allowing the programmer to concentrate on application logic.

This release of the library supports version 1.0 of the API.

2 Configuration

Use the following parameters to configure the library. All API calls within the current scope are affected.

2.1 Basic Configuration

Before making any API calls, the programmer must configure the username and password to use to authenticate with All communication takes place over SSL, so username and password are secure during transmission over the Internet.

Note that, in the current version of the API, it is only possible to query/manipulate information in the authenticated account.

current-username : (parameter string)

Sets/retrieves the username to use for subsequent API calls.

current-password : (parameter string)

Sets/retrieves the password to use for subsequent API calls.

For example:

  (parameterize ([username "untyped"]

                 [password "password"])

    ; ... authenticated API calls go here ...)

2.2 Advanced Configuration

current-base-url : (parameter string)

The base URL of the API. By default this is:


Note the following:

current-throttle : (parameter throttle)

The throttle control to use to limit the rate at which API requests are made. can get touchy if you make too many requests too quickly. The documentation states that you must leave a minimum of 1 second between requests, otherwise you will be throttled for up to a few minutes. Experience has shown that persistent use of some of the more "expensive" API requests (such as all-posts) can cause to throttle clients even if they respect this 1 second gap.

The current-throttle parameter takes a throttle structure that is used to rate limit requests. The default value limits the client to the maximum of 1 request per second. You can change this default value if you find you are frequently being throttled by See Internal Procedures for more information.

2.3 Debug Configuration

The following parameters pare provided to help debug problems with the library:

dump-request-urls? : (parameter boolean)

If this parameter is set to #t, the URLs of API calls are printed immediately before each call is made.

dump-sxml-responses? : (parameter boolean)

If this parameter is set to #t, the SXML versions of all responses are printed as they are parsed. Note that this requires the XML response from to be well-formed.

3 API Wrappers

3.1 Special Values

empty : symbol

The unique symbol empty is used to represent an unspecified argument to an API call (this is because some API calls take optional boolean arguments).

3.2 Result Structures

The following structures are used to encapsulate data returned by API calls. The same structures can also optionally be used as arguments to some API calls:

(struct post (url description extended tags date))

  url : string

  description : string

  extended : (U string #f)

  tags : (list-of string)

  date : (U srfi-19:date #f)

A post, comprising a bookmark and some metadata:

(struct bundle (name tags))

  name : string

  tags : (list-of string)

A tag bundle: a named collection of tags. Note that bundles may not be used in place of tags, either as members of other bundles or as tag arguments to API calls. This limits their usefulness in the API, although they still appear on the web site.

3.3 Exceptions

The following exceptions may be raised by any API procedure call:

(struct (exn:delicious exn) ())

Abstract exception supertype. Subtypes of this exception represent failures that are typically the fault of the user, rather than this library or itself.

Applications should respond to exceptions of this type by displaying a "you messed up" style dialog box or feedback message.

(struct (exn:fail:delicious exn) ())

Abstract exception supertype. Subtypes of this exception represent failures that are typically the fault of this library or

Applications should respond to exceptions of this type by displaying an "unexpected error" style dialog box or feedback message.

(struct (exn:delicious:auth exn:delicious) ())

Raised if returns an HTTP 403 response. This typically means the username/password were invalid.

(struct (exn:fail:delicious:throttled exn:fail:delicious) ())

Raised if returns an HTTP 503 response. is very sensitive to request spamming or over-use. This library contains an auto-throttling element that prevents applications making more than the one permitted request per second, but excessive use of "expensive" requests such as all-posts can still trigger throttling.

Applications should respond to exceptions of this type by backing off for 30 seconds to a few minutes, until switches its throttle protection off again.

(struct (exn:fail:delicious:parse exn:fail:delicious) (fragment))

  fragment : sxml

Raised if the library was unable to parse an XML response. This implies the result was well-formed XML with an unexpected structure. The fragment field contains the problematic SXML fragment.

If you get one of these, it’s time to switch on the dump-sxml-responses? parameter and start hunting for bugs in this library. Note that, while bug reports are gratefully received, bug reports and fixes are infinitely preferable.

3.4 API Procedures

The following procedures are wrappers for the various API calls. All calls require the current-username and current-password parameters to be set.

(last-updated)  srfi-19:date

Returns the (SRFI-19) date of the last post to the account.

(get-tags)  (alist-of string integer)

Returns an association list of tags to number of uses.

(rename-tag! old-name new-name)  void

  old-name : string

  new-name : string

Renames a tag and propagates the change to all related posts. For example:

  > (length (get-posts "untyped"))


  > (length (get-posts "un-typed"))


  > (rename-tag! "un-typed" "untyped")

  > (length (get-posts "untyped"))


  > (length (get-posts "un-typed"))


(get-posts [tag date url])  (list-of post)

  tag : (U string empty) = empty

  date : (U srfi-19:date empty) = empty

  url : (U string empty) = empty

Returns all posts matching the arguments:

If all arguments are empty, posts are returned from the most recent day of posting.

(recent-posts [tag count])  (list-of post)

  tag : (U string empty) = empty

  count : (U integer empty) = empty

Returns a list of the most recent posts:

The default value of count is 15.

(all-posts [tag])  (list-of post)

  tag : (U string empty) = empty

Returns all posts.

The documentation notes: "Please use sparingly. Call the update function to see if you need to fetch this at all." Frequent use can result in throttling.

(post-dates [tag])  (alist-of srfi-19:date integer)

  tag : (U string empty) = empty

Returns an association list of post dates to number of posts made on that day.

(add-post! post [replace? shared?])  void

  post : post

  replace? : (U boolean empty) = empty

  shared? : (U boolean empty) = empty

Creates a new post given a post structure.

This procedure delegates to add-post/raw! to do most of the work. Fields in the post are automatically mapped to empty when appropriate.

(add-post/raw! url description [extended tags date replace? shared?])  void

  url : string

  description : string

  extended : (U string empty) = empty

  tags : (U (list-of string) empty) = empty

  date : (U srfi-19:date empty) = empty

  replace? : (U boolean empty) = empty

  shared? : (U boolean empty) = empty

Creates a new post given the constituent parts of a post structure. url, description, extended, tags and date have the same purpose as the relevant fields of post.

(delete-post! post)  void

  post : post

Deletes an existing post given a post structure.

(delete-post/raw! url)  void

  url : string

Deletes an existing post given a URL.

(all-bundles)  (list-of bundle)

Returns a list of tag bundles in the current account.

(update-bundle! bundle)  void

  bundle : bundle

Creates or updates a tag bundle given a bundle structure. This procedure delegates to update-bundle/raw! to do most of the work.

(update-bundle/raw! name tags)  void

  name : string

  tags : (list-of string)

Creates or updates a tag bundle given its constituent parts.

(delete-bundle! bundle)  void

  bundle : bundle

Deletes a bundle given a bundle structure.

(delete-bundle/raw! name)  void

  name : string

Deletes a bundle given its name.

4 Internal Procedures

4.1 Throttle

The file "" contains procedures that control the rate at which the client sends requests to

(make-throttle delay)  throttle

  delay : integer

Creates a throttle structure that manages a queue of requests to run "throttled sections" of code. The throttle responds to requests in the order in which they are received, ensuring that delay milliseconds are allowed to pass between the end of one call and the beginning of the next. This behaviour is enforced in single- and multi-threaded environments.

Use this procedure in conjunction with the current-throttle parameter to change the rate at which the client makes calls to For example:

  (let ([throttle (make-throttle 2000)])

    (parameterize ([current-throttle throttle])

      ; ... API calls throttled to at most 1 every 2 seconds ...)

    (kill-throttle! throttle))

(call-with-throttle throttle thunk)  any

  throttle : throttle

  thunk : (-> any)

Makes a throttled call to thunk. call-with-throttle sends a message to throttle, asking if it can run the throttled section in thunk. throttle adds the requests to its queue and behaves as described in the documentation for make-throttle above.

(throttle? x)  boolean

  x : any

Returns #t if x is a throttle, #t otherwise.

(throttle-delay throttle)  integer

  throttle : throttle

Returns the delay enforced by throttle in milliseconds.

(kill-throttle! throttle)  void

  throttle : throttle

throttle objects use threads to handle requests. When you have finished using a throttle, you can (and should) call this procedure to kill its thread and free up the system resources it was using. Once a throttle has been killed, it can no longer be used in calls to call-with-throttle.

You can also kill a throttle by shutting down the custodian that was current when it was created.

(throttle-alive? throttle)  boolean

  throttle : throttle

This procedure determines whether or not a throttle has been killed with the kill-throttle procedure.