Twitter-GLib New API Design

0.9.x issues

  • Written for a specific use case (Tweet client)
  • Use libsoup directly
  • Only plain Web authentication
    • Twitter is going to deprecate plain WebAuth in favour of OAuth

  • Not-really-async API
  • Master object (TwitterClient) which controls the whole API

  • Defer too much to layers on top

New API tenets

  • Be more GIO-like
  • Be really asynchronous
  • Use OAuth
  • Move methods to objects
  • Use more platform libraries
    • e.g. keyring to store token/secret pair

Upstream reference: Twitter API Documentation

Hierarchy

  GObject
  +---- TwitterSession - Session handler (authentication)
  +---- TwitterAccount - Account management (verify credentials)
  +---- TwitterUser    - User data structure
  +---- TwitterStatus  - Status data structure

TwitterSession

  TwitterSession *session;

  /* recovers the default auth credentials from the keyring */
  session = twitter_session_new (user_agent);

  /* defers the auth credentials to the calling code */
  session = twitter_session_new_with_credentials (user_agent, token, secret);

/!\ Open Questions:
Do we make gnome-keyring optional and create different storage types? Can we use extension points for the secret storage and delegate to runtime modules?

TwitterAccount

  • Recover the Account for the session:

  TwitterAccount *account;

  /* the account for the session credentials; the Account object is
   * created immediately
   */
  account = twitter_session_get_account (session);
  • Status update (synchronous version):

  twitter_account_update_status (account, status_message, cancellable, &error);
  • Status update (asynchronous version):

  static void
  update_status_cb (GObject      *gobject,
                    GAsyncResult *result,
                    gpointer      user_data)
  {
    TwitterAccount *account = TWITTER_ACCOUNT (gobject);
    TwitterStatus *new_status;
    GError *error = NULL;

    new_status = twitter_account_update_status_finish (account, result, &error);
    if (error)
      {
        g_message ("Unable to update status: %s", error->messag);
        g_error_free (error);
        return;
      }

    /* handle new status */

    g_object_unref (status);
  }

    ...
    twitter_account_update_status (account, status_message, cancellable, update_status_cb, NULL);
  • Verifying credentials (asynchronous version):

  static void
  verify_credentials_cb (GObject      *gobject,
                         GAsyncResult *result,
                         gpointer      user_data)
  {
    TwitterAccount *account = TWITTER_ACCOUNT (gobject);
    TwitterUser *self;
    GError *error = NULL;

    self = twitter_account_verify_credentials_finish (account, result, &error);
    if (error)
      {
        ...
      }

    ...

    g_object_unref (self);
  }

  ...
    twitter_account_verify_credentials (account, cancellable, verify_credentials_cb, NULL);

TwitterUser

Maps the Twitter user object, but it also has methods for retrieving the user's timeline, friends and followers, etc.

  • User timeline (synchronous version):

  GList *statuses;

  statuses = twitter_user_get_user_timeline (user, cancellable,
                                             since_id, max_id,
                                             count,
                                             page,
                                             &error);
  for (l = statuses; l != NULL; l = l->next)
    {
      TwitterStatus *status = l->data;
    }

/!\ Open Questions:
Pagination vs. Iteration: Twitter is moving towards iteration, so the page argument might be ignored until they have settled
Maybe use an intermediate object holding the status list which effectively implements iteration-over-pagination for the time being and then switches over with Twitter

TwitterStatus

Maps the Twitter status object.

Attic/TwitterGlib/NewApiDesign (last edited 2013-11-22 20:10:46 by WilliamJonMcCann)