Technology Experience
.NET World

Come ottenere un feed RSS con le Twitter API in versione 1.1

Da circa una decina di giorni, Twitter ha apportato grossi cambiamenti alle proprie API, cambiamenti che hanno afflitto me – come developer di app per Windows Phone e Windows 8 – e non solo me. Basta una googlata per venire a sapere che chiunque abbia sviluppato app (per OS mobile, quindi iOS ed Android, ma non solo) che accedono a Twitter sia rimasto pesantemente fregato.

Prima infatti era possibile effettuare una chiamata via http al seguente url:
http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=IgorDamiani

Con questo url si otteneva un bel feed RSS dell’utente Twitter passato come parametro, in questo caso “IgorDamiani”, cioè me stesso. Il feed era quindi consumabile dalle app per visualizzare tutti i tweet di un certo utente. Questa cosa era valida fino a 10 giorni fa, appunto. Adesso dà un messaggio inequivocabile: “The Twitter REST API v1 is no longer active. Please migrate to API v1.1.”. Morale: bisogna usare le API 1.1, che sostanzialmente hanno introdotto due cambiamenti:

Bella fregatura, vero? Ovviamente la soluzione c’è, basta adeguarsi, e fortunatamente io sono partito con qualche mese di anticipo, facendo prima di tutto in modo di far puntare tutte le mie app ad un unico url, hostato sui miei server, in modo tale da diventare trasparente rispetto ai cambiamenti apportati da Twitter. Quindi, diciamo, se ho 60 app che utilizzano Twitter, non ho cablato in ciascuna app l’url di Twitter, ma un mio url, che sarà sempre valido, dal momento che sono io a gestirlo e farò di tutto per non cambiarlo mai! Quindi, supponiamo, io ho un url nel formato seguente:

http://mioserver/Dammi_Il_FeedRssTwitter?id=<TwitterUsername>

Ho rimosso il collegamento perchè comunque non sarebbe valido. Questo url è un entry-point per tutte le mie app che devono mostrare un feed Twitter. Quindi, l’app “I Love Milan” per Windows Phone chiamerà l’url usando “acmilan”, l’app “Nove Colli” chiamerà l’url con “novecolli”, mentre l’app “Piloti Virtuali Italiani” (per Windows Phone e Windows 8) chiamerà l’url usando “pvi_org”. Questo è un mio servizio, che fa da adapter tra ciò che Twitter espone con le sue API e ciò che le mie app si aspettano. Quindi: con le API 1.0 invocavo Twitter, ottenevo un RSS e lo passavo così com’era alle mie app. Cone le API 1.1 invoco Twitter con l’autenticazione, ottengo un JSON, costruisco da zero un feed RSS in formato XML e lo restituisco a chi di dovere.

Passo 1 – Come ottenere il JSON

Il primo passo è utilizzare questa classe JsonDownloader che ho scritto questa mattina (e basandomi su questo articolo su CodeProject), molto semplice, che fa la chiamata verso Twitter, in modo autenticato, che vi restituisce una string, che in pratica è il JSON da parserizzare.

Lo zip contiene un file JsonDownloader.cs, da includere nel verso progetto e modificare come necessario. L’unica accortezza – cosa che prima non era necessaria – è che dovete necessariamente registrare la vostra app su https://dev.twitter.com/, per ottenere quattro key da inserire nel codice per l’autenticazione OAuth, ovvero:

  • Consumer Key
  • Consumer Secret
  • Access Token
  • Access Token Secret

Nel .cs che scaricate gli oggetti string ci sono già, pronti all’uso, vanno solo valorizzati correttamente.

Passo 2 – Parserizzare lo JSON ed ottenere l’XML del feed RSS

Usando la libreria Json.NET, reperibile su Twitter, le cose sono semplici, ma mica tanto. Innanzitutto, immaginiamo una chiamata del genere:

string rss = RssParser.GetRss(json, id);

Da questo si evince che abbiamo una classe statica RssParser, che espone un metodo pubblicato GetRss. Il cui codice è il seguente:

public static string GetRss(string json, string screenName)
{
    try
    {
        if (!string.IsNullOrEmpty(json))
        {
            json = "{"root": " + json + "}";

            var result = JObject.Parse(json);
            var elements = (JArray)result.Children().Children().FirstOrDefault();
            var first = ((JObject)elements.FirstOrDefault()).Property("created_at").Value.ToString();
            var firstDate = RssItem.ParseDateTime(first);

            StringBuilder bld = new StringBuilder();
            string feed = GetRssHeader();
            string itemBlock = GetRssItemBlock();
            bld.AppendFormat(feed, screenName, firstDate, screenName);

            foreach (JObject elem in elements)
            {
                RssItem item = RssItem.Get(elem);

                if (item != null)
                {
                    bld.AppendFormat(itemBlock, item.Title, screenName, item.Id,
                        item.FormattedDate, item.FormattedDate,
                        screenName, item.Id);
                }
            }

            bld.Append("</feed>");

            return bld.ToString();
        }
        else
        {
            return string.Empty;
        }
    }
    catch (Exception exc)
    {
        return exc.ToString();
    }
}

Questo metodo esplora lo JSON e restituisce la string del feed RSS. Navigando sugli oggetti JObject e JArray, e nelle relative proprietà, costruisco di fatto. Ci sono due metodi GetRssHeader() e GetRssItemBlock() che non fanno altro che recuperare delle embedded resource del progetto: di fatto contegono rispettivamente lo XML di intestazione del feed XML:

<?xml version="1.0" encoding="utf-8" ?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<title>Twitter / {0}</title>
<id>tag:twitter.com,2007:Status</id>
<link type="text/html" rel="alternate" href="http://twitter.com"/>
<updated>{1}</updated>
<subtitle>Twitter updates from {2}.</subtitle>

e del blocco da ripetere per ciascun tweet:

<item>
<title>{0}</title>
<content type="html">content</content>
<id>tag:twitter.com,2013:http://twitter.com/{1}/status/{2}</id>
<pubDate>{3}</pubDate>
<updated>{4}</updated>
<link type="text/html" rel="alternate" href="http://twitter.com/{5}/status/{6}" />
</item>

All’interno del ciclo foreach viene costruito un oggetto RssItem:

public class RssItem
{
    static CultureInfo culture = new CultureInfo("en-US");

    public string Id { get; set; }
    public string Title { get; set; }
    public DateTime Date { get; set; }
    public string FormattedDate { get; set; }

    public static RssItem Get(JObject obj)
    {
        RssItem result = new RssItem();
        result.Id = obj.Property("id").Value.ToString();
        result.Title = obj.Property("text").Value.ToString();
        result.Date = ParseDateTime(obj.Property("created_at").Value.ToString());
        result.FormattedDate = result.Date.ToString("dd/MM/yyyy HH.mm.ss");

        return result;
    }

    public static DateTime ParseDateTime(string value)
    {
        // Fri Jun 21 10:22:17 +0000 2013
        try
        {
            int index = value.IndexOf('+');

            if (index != -1)
            {
                // Devo rimuovere il "+0000 "
                string partToRemove = value.Substring(index, 6);
                value = value.Replace(partToRemove, string.Empty);
            }

            return DateTime.ParseExact(value, "ddd MMM dd H:mm:ss yyyy", culture, System.Globalization.DateTimeStyles.None);
        }
        catch (Exception)
        {
            return DateTime.Now;
        }
    }
}

Il metodo pubblico Get restituisce un’istanza di RssItem, valorizzata in base al JObject corrente. All’interno ci sono un po’ di operazioni di parsing, soprattutto sulle date, che andrebbero magari riviste per essere ottimizzate, ma per adesso funzionano!

Passo 3 – Fine!

E fine. A questo punto abbiamo una string che in pratica è il feed RSS da dare in pasto alle nostre applicazioni. Se avete qualche decina di app che improvvisamente avevano smesso di funzionare a causa di questa breaking change di Twitter, le vedrete riprendere vita di colpo! La cosa molto interessante che il tutto è gestito in modo centralizzato, e non sarete obbligati a rilasciare nuove versioni delle vostre app, inseguendo i cambiamenti di Twitter. Qualsiasi modifica che si renderà necessaria è centralizzata con questo codice, e per le app è del tutto trasparente.

Send to Kindle

Igor Damiani

La sua passione per l'informatica nasce nella prima metà degli anni '80, quando suo padre acquistò un Texas Instruments TI-99. Da allora ha continuato a seguire l'evoluzione sia hardware che software avvenuta nel corso degli anni. E' un utente, un videogiocatore ed uno sviluppatore software a tempo pieno. Igor ha lavorato e lavora anche oggi con le più moderne tecnologie Microsoft per lo sviluppo di applicazioni: .NET Framework, XAML, Universal Windows Platform, su diverse piattaforme, tra cui spiccano Windows 10 piattaforme mobile. Numerose sono le app che Igor ha creato e pubblicato sul marketplace sotto il nome VivendoByte, suo personale marchio di fabbrica. Adora mantenere i contatti attraverso Twitter e soprattutto attraverso gli eventi delle community .NET.

2 pensieri riguardo “Come ottenere un feed RSS con le Twitter API in versione 1.1

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.