vendredi 7 mai 2010

Exposer une API REST/XML avec Play!

Aujourd'hui nous allons voir comment exposer simplement du contenu XML (ou JSON, ou autre) avec le framework Play!.
Les URL de Play! étant RESTful par essence, il devient très facile de créer une petite API REST/XML coinjointement à l'interface Web d'une application Play!.
Voyons comment procéder.

Prenons l'exemple d'une bibliothèque musicale. Notre modèle comporte des albums, des artistes et des genres.
La classe Album se présente comme ceci :
@Entity
public class Album extends Model {
 public String name;
 @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
 public Artist artist;
 public Date releaseDate;
 @Enumerated(EnumType.STRING)
 public Genre genre;

Le genre est une simple Enum, définie comme cela :
public enum Genre {
    ROCK, METAL, JAZZ, BLUES, POP, WORLD, HIP_HOP, OTHER
}

Nous voulons définir une URL qui renvoie lors d'un GET la liste des albums au format XML pour un genre donné.
Pour cela nous devons modifier le fichier routes :
GET /website/albums/{genre}       Application.list
GET /albums/{genre}   Application.listXml(format:'xml')

La première ligne correspond à la page HTML(non présentée dans cet article) affichant la liste des albums disponibles : le format n'étant pas spécifié, le rendu se fera avec une page HTML.
Ici c'est la deuxième ligne qui nous intéresse. Le paramètre (format:'xml') indique que la méthode render() du contrôleur devra chercher un fichier nommé listXml.xml.
Le paramètre {genre} sera récupéré dans l'URL et passé au contrôleur.

NB :
Il est possible d'utiliser une seule méthode dans le contrôleur si les paramètres requis et les traitements sont identiques pour les 2 types de rendus.
Dans notre cas il se peut qu'on ajoute des paramètres à la version HTML ultérieurement, sans vouloir impacter le rendu XML, par exemple :
GET /albums/{genre}/{first}/{count} Application.list
J'ai donc opté pour une séparation du rendu dans deux méthodes distinctes.

Le code de la méthode Application.listXml est le suivant :
public static void listXml(String genre) {
        Genre genreEnum = Genre.valueOf(genre.toString().toUpperCase());
        List<Album> albums= Album.find("byGenre",genreEnum).fetch();
        render(albums);
    }

Je recherche simplement les albums correspondant au genre passé en paramètre, et je demande le rendu de la liste. Au passage on voit la simplicité d'utilisation de JPA avec Play!! Le rendu sera fait dans le fichier portant le nom de la méthode et l'extension xml : listXml.xml.
Ce template, placé dans le repertoire app/views, est défini comme ceci :
   
#{list albums, as:'album'}
    <album>
        <artist>${album.artist.name}</artist>
        <name>${album.name}</name>
        <release-date>${album.releaseDate.format('yyyy')}</release-date>
        <genre>${album.genre.toString()}</genre>
    </album>
#{/list}


Voilà, cela suffit pour exposer nos albums en XML. En respectant le pattern d'URL défini dans le fichier routes, par exemple en appelant http://localhost:9000/albums/rock, on obtient le résultat suivant :

<albums>
   <album>
      <artist>Nirvana</artist>
      <name>Nevermind</name>
      <release-date>1991</release-date>
      <genre>ROCK</genre>
   </album>
   <album>
      <artist>Muse</artist>
      <name>Origin of Symmetry</name>
      <release-date>2001</release-date>
      <genre>ROCK</genre>
      </album>
   <album>
      <artist>Muse</artist>
      <name>Black Holes and Revelations</name>
      <release-date>2006</release-date>
      <genre>ROCK</genre>
   </album>
</albums>

Dans le prochain article nous verrons comment envoyer du contenu XML en POST pour ajouter des albums à notre bibliothèque. Lire la suite du tutoriel