Créez facilement des flux RSS depuis une application Scala

Motivations

Lors de la mise en place d’un site web proposant des informations susceptibles d’évoluer au cours du temps (une grande partie des sites donc), il peut être intéressant d’intégrer un ou des flux RSS. Vos utilisateurs n’ont alors plus qu’à ajouter le flux qui les intéresse à leur lecteur préféré afin d’être informés facilement de nouvelles mises à jour.

Un flux RSS n’est au final qu’un fichier XML suivant quelques spécifications particulières. Ces spécifications, (assez courtes) sont actuellement en version 2.0.

Voulant intégrer un flux RSS sur l’un des sites que je développe actuellement en Scala/PlayFramework, je me suis rendu compte qu’il n’existait pas de solution purement Scala pour en ajouter facilement. Il existe bien une solution en Java (et donc utilisable en Scala) qui s’appelle Rome, cependant l’API qu’elle propose n’est pas très “fluent”, de plus le projet semble être  à l’abandon…

L’une des solutions proposées sur StackOverflow pour générer les flux est d’utiliser directement les XML literals de Scala, une fonctionnalité bien pratique qui permet d’écrire du XML brut de décoffrage (même pas entre guillemets !) dans un fichier Scala et de pouvoir directement l’assigner dans une variable.

1
2
3
4
5
6
// cette variable sera utilisé dans le reste des exemples
// et représente les éléments à insérer dans le flux
val items = List(("title1", "content1", new URL("http://link1.com"),
                      "author1@site1.com"),
                 ("title2", "content2", new URL("http://link2.com"),
                      "author2@site2.com"))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
val rssXmlLiterals =
  ‹rss version="2.0"
    ‹channel›
      ‹title›some title‹/title›
      ‹description›some description‹/description›
      ‹link›http:∕∕someli.nk‹/link›
      ‹webMaster›somebody@somewhere.com‹/webMaster›
      {
        for (item ‹- items) yield {
          ‹item›
            ‹title›{ item._1 }‹/title›
            ‹description›{ item._2 }‹/description›
            ‹link›{ item._3 }‹/link›
            ‹author›{ item._4 }‹/author›
          ‹/item›
        }
      }
    ‹/channel›
  ‹/rss›

Cette méthode présente cependant plusieurs inconvénients :

  • Cela reste assez verbeux, car on écrit au final du XML,
  • Il est compliqué de vérifier que le fichier généré est bien un flux RSS valide (enchaînement des balises, présence des éléments obligatoires, …) et cela risque de poser encore plus de problèmes lors de la maintenance de l’application,
  • On peut se poser des questions sur la pérennité des XML literals dans Scala.

C’est pourquoi j’ai codé une petite librairie :  SSU (pour Scala Syndication Utils) qui permet d’écrire des flux RSS en Scala et qui vous assure que le XML que vous générez est compatible avec la spécification RSS.

Implémentation

La libraire propose une API utilisant le pattern  “Type-safe Builder” afin de garantir à la compilation que vous fournissez suffisamment de données pour générer un flux RSS valide.

En pratique, pour générer un flux RSS avec SSU voila ce que vous avez à faire :

1
2
3
4
5
6
7
8
val rssSsu = (
  RssFeed("some title", new URL("http://someli.nk"), "some description")
  withWebMaster "somebody@somewhere.com"
  withItems (items map (item ⇒ RssItem
    withTitle item._1
    withDescription item._2
    withLink item._3
    withAuthor item._4))).toXml

Par contre, si vous ne respectez par certaines obligations du format, vous obtiendrez une erreur de compilation, le code suivant par exemple ne compile par parce qu’un item d’un flux RSS doit avoir au moins un titre ou une description :

1
2
3
4
5
val rssNotValid = (
  RssFeed("some title", new URL("http://someli.nk"), "some description")
  withItems (items map (item ⇒ RssItem // erreur
    withLink item._3
    withAuthor item._4))).toXml

Pour faire compiler le code, il suffit de faire un appel à l’une des méthodes withTitle ou withDescription sur le RssItem.

Mais quelle est cette magie ?

Cette magie, c’est juste des type paramétrés, mais ici, ils sont cachés ! La classe RssItem est paramétrée par ce que l’on appelle un “phantom type” (un type utilisé uniquement pour paramétrer une classe mais jamais instancié), et chaque appel de méthode sur RssItem retourne une nouvelle instance, sans charger le type paramétré. Sauf dans le cas de l’appel à l’une des 2 méthodes withTitle ou withDescription qui a pour effet de retourner un RssItem avec un type paramétré différent. La méthode withItems de RssFeed prends comme argument une liste de RssItem dont le type paramétré reflète la validité (ici la présence d’un titre ou d’une description) des éléments. Une erreur de compilation est donc lancée si la liste de RssItem passée n’est pas paramétrée correctement (= s’il n’y a pas de titre ou de description). Pour plus d’information sur le pattern “Type-safe Builder”, je vous invite à lire cet article.

Le code source de la libraire est disponible sur github.com/fredszaq/ssu, et le dépôt est construit et testé a chaque push par travis-ci.org. La mise en place de Travis est super simple et permet facilement d’ajouter de l’intégration continue à un projet hébergé sur Github, un must have pour n’importe quel projet open source !

Et après ?

Il reste encore un peu de boulot avant que la librairie soit réellement utilisable :

  • Déploiement d’une version sur maven central,
  • Meilleure gestion des adresses mail, qui sont pour le moment des strings non validées,
  • Peaufinage des api, je me pose notamment des questions au niveau de l’exposition ou non de méthodes prenant des Option[] en argument,
  • Support de Java (j’ai fait quelques tests, il va falloir rajouter quelques classes de support).

Si vous avez des idées, j’attends vos pull requests !

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Ce contenu a été publié dans Non classé, avec comme mot(s)-clef(s) , , , , , , . Vous pouvez le mettre en favoris avec ce permalien.

Laisser un commentaire