17 December 2015

POC SPA Angular & API Platform

Le but de ce POC est de travailler sur une Single Page Application en Angular qui communique avec une API utilisant l’API Platform de Kévin Dunglas sous Symfony2.

À l’occasion d’un projet pour un nouveau client, l’équipe AppVentus a saisi l’occasion de découvrir un nouvel environnement technique. Travaillant d’habitude sur son propre DCMS, Victoire, il a été décidé de réaliser ce POC pour mettre en pratique 2 axes de notre Lab technique :

  • affiner les connaissances liées au web sémantique en utilisant les environnements suivants : Schema.org & API REST de type HATEOAS
  • tester la rapidité et la performance d’une SPA couplée à une API

Les technos utilisées en back :
- Symfony2 : https://symfony.com
- API Platform : https://api-platform.com
- NelmioCorsBundle : https://github.com/nelmio/NelmioCorsBundle
- NelmioApiDocBundle : https://github.com/nelmio/NelmioApiDocBundle
- JsonLD : https://github.com/lanthaler/JsonLD
- LexikJWTAuthenticationBundle : https://github.com/lexik/LexikJWTAuthenticationBundle
- FOSUserBundle : https://github.com/FriendsOfSymfony/FOSUserBundle


Les technos utilisées en front :
- AngularJS : https://angularjs.org
- Angular Material : https://material.angularjs.org
- Restangular : https://github.com/mgonto/restangular
- Satellizer : https://github.com/sahat/satellizer
- Autres lib Angular : angular-translate, angular-ui-router, angular-toastr


Outils de dev :
- Hydra console : https://github.com/lanthaler/HydraConsole
- HTTPie : https://github.com/jkbrzt/httpie


Concepts :
- Schema.org : https://fr.wikipedia.org/wiki/Schema.org
- Hypermedia REST Application : https://en.wikipedia.org/wiki/HATEOAS
- Hydra : http://www.hydra-cg.com
- JSON-LD : http://json-ld.org
- JSON web token : http://jwt.io

Proof of concept

Le fonctionnement de ce POC est le suivant :

  • 3 types de User peuvent se connecter : des Farmer, des Customer et des Admin.
  • Une liste de Food est préchargée via des fixtures. On y trouve deux types de Food : Fruit et Vegetable.
  • Les visiteurs peuvent s’enregistrer puis se connecter. Ils auront le rôle de Customer.
  • Les Admin peuvent se connecter et accéder à des fonctionnalités qui leur sont réservées : lister, modifier et ajouter des utilisateurs; lister, modifier et ajouter des Basket qui comprennent un nombre illimité de Food avec une quantité déterminée pour chaque élément.
API Plateform schéma POC

L’API

Api Platform

Api Platform est un projet de Kevin Dunglas développé sous Symfony2. Ce projet consiste principalement à rassembler de nombreuses briques fonctionnelles pour proposer une application REST de type HATEOAS. API Platform est aussi livré avec un bundle très intéressant : schema-generator.

Schema generator & Schema.org

Le générateur de schéma d’API Platform est une ligne de commande qui permet d’automatiser la génération du modèle de données à partir des types de données répertoriées sur Schema.org.

Schema.org est née de l’initiative des principaux moteurs de recherche (Google, Bing, Yahoo). Le site propose de répertorier les types de données indexables par les moteurs de recherche. Cela permet de donner plus de sens aux données présentes sur le web et s’intègre dans la mouvance du web sémantique.

En préparant le modèle de données de notre API selon Schema.org, on pourra plus facilement donner un sens aux données qui pourront être indexées sur notre SPA.

Pour nos utilisateurs, nous utilisons le type Person (https://schema.org/Person) avec ses propriétés name, description, url, birthDate et gender. Si besoin, nous pourrons utiliser ces informations ultérieurement pour mieux référencer les pages utilisateurs.

Après génération du modèle via la commande generate-types, nous obtenons une entité Person (que nous avons renommé User) avec les annotations suivantes :

On peut évidemment ajouter des entités et propriétés Doctrine qui ne sont pas issues du modèle généré à partir de Schema.org.

HATEOAS

Le principe d’une application REST HATEOAS est de faciliter les interactions client/serveur via l’Hypermedia. Le client REST (ici notre application Angular) peut avoir connaissance de l’ensemble des méthodes qui lui sont mises à disposition par l’API. En interrogeant la root URL de l’API, on accède à un “Entrypoint” qui liste toutes les routes disponibles et leurs méthodes (POST|GET|PUT|DELETE|PATCH).

Pour donner une dimension Hypermedia à API Platform, le format JSON-LD est utilisé. Le concept principal de ce format est de lier entre-elles les données disponibles sur internet et leur donner un sens interprétable par n’importe quelle machine.

Si on interroge la première URL fournie par l’API, à savoir /customers en GET, on obtient le résultat suivant :

Chaque résultat de l’API nous donne son lot d’informations particulièrement utiles pour le client REST.

  • @id : c’est l’identifiant du noeud JSON. On voit dans cet exemple que le premier Customer retourné dans cette liste dispose d’un @id. Cet @id va nous permettre à la fois de connaître la route de l’API pour accéder à toutes ses informations mais aussi de savoir comment le lier à une autre entité. Par exemple, si l’on souhaite sauvegarder un nouveau Basket pour ce Customer, on interrogera en POST l’url /baskets avec le payload user=”/customers/d199fff0–9a8b-11e5-a850–8479d0aae065".
  • @context : c’est le contexte lié à un noeud JSON. Dans le cas d’API Platform, en utilisant le générateur de schéma basé sur Schema.org, on aura automatiquement accès au contexte de chaque donnée via une simple URL. Par exemple, pour notre entité Customer, nous avons utilisé plusieurs propriétés de Schema.org. En interrogeant l’url /contexts/Customer, on retrouve alors les informations suivantes :
    birthDate: https://schema.org/birthDate
    description: https://schema.org/description
    gender: https://schema.org/gender
    name: https://schema.org/name
  • @hydra : les propriétés hydra sont un ensemble de normes Hypermedia utilisées ici pour la pagination des résultats

Nelmio Api Doc

NelmioApiDocBundle est installé par défaut avec API Platform. Ce bundle permet d’automatiser l’écriture de la documentation de notre API.

Api documentation
Api documentation

Grâce à Schema.org, une grande partie de notre documentation est déjà écrite. Il reste tout de même un peu de travail pour rendre cette documentation exhaustive.

JSON Web Token

Les web tokens sont des hash de plus de 100 caractères qui servent de signature pendant une période déterminée. Ce token transitera dans le header de chaque requête entre le client et le serveur et permet d’éviter le stockage de cookies ou la création de sessions.

Le JSON Web Token est un hash en trois parties :

  • Un header composé d’un objet javascript indiquant quel algorithme est utilisé pour le hash. Le tout encodé en base64.
  • Le payload composé d’un objet javascript contenant les informations utiles à l’authentification (sujet, date de création, date d’expiration, etc.) et toute autre information qui vous paraîtra utile. Le tout encodé en base64 aussi.
  • La signature qui est une concaténation du header et du payload encodée selon l’algorithme défini dans le header.
JSON Web Token

Nelmio Cors

Si vous décidez d’héberger votre SPA et votre API sur des hosts différents, il faudra configurer Nelmio Cors pour autoriser les requêtes provenant de votre SPA.

Single Page Application

Front Angular

Restangular

Restangular est une librairie AngularJS qui simplifie la communication entre une application front et une API REST. Par exemple, pour récupérer la liste des utilisateurs, il suffit simplement d’écrire : Restangular.all(‘users’).getList()

Cette librairie est suffisamment flexible pour écrire n’importe quel type de requête compréhensible par l’API.

Un léger travail de configuration sera toutefois nécessaire pour configurer le Provider de Restangular afin qu’il interprète correctement les réponses au format JSON-LD de notre API. Pour cela nous nous sommes inspiré du travail réalisé par Kévin Dunglas sur le fichier app/app.js de son tutoriel.

Satellizer

Satellizer est une librairie complète d’authentification en AngularJS basée sur le stockage d’un JSON web token. En utilisant simplement le code suivant : $auth.setToken(response.data.token) on stocke le token de l’utilisateur en local storage (configuration par défaut), lui donnant les droits pour accéder aux fonctionnalités qui lui sont réservées.

Satellizer permet aussi d’implémenter facilement la connexion via les API de Facebook, Google, Linkedin et bien d’autres.

Problèmes rencontrés

Durant le développement de cette application, l’équipe n’a pas rencontré de point bloquant. Un seul aspect technique nous a retardé : la sauvegarde des entités associées en OneToMany et ManyToMany. En effet, aucun problème pour la sauvegarde des OneToOne et ManyToOne mais dès lors que nous souhaitions sauvegarder une Collection d’entités, rien ne se passait. Nous avons eu quelques difficultés à trouver des informations à ce sujet dans la doc d’API Platform. Après quelques heures de debug infructueuse dans l’api-bundle, nous nous sommes aperçu qu’il existait une solution pour à la fois récupérer et sauvegarder les entités associées : les Serialization groups.

Dans notre cas, nous souhaitions, pour un Basket donné, récupérer l’ensemble de ses Food via l’entité FoodBasket. En appelant l’un des Basket, nous obtenions la réponse suivante :

Tous les FoodBasket étaient bien présents mais il nous fallait plus de détail sur chacun pour savoir de quel Food il s’agissait sans devoir exécuter de nouvelles requêtes.

Nous avons donc adapté la config de notre entité pour lui ajouter un Group de Serialization mais aussi de Deserialization (pour la sauvegarde).

Puis, pour chaque propriété de FoodBasket dont nous souhaitions connaître la valeur, nous leur avons ajouté l’annotation Groups du Serializer de Symfony avec la valeur du groupe déclarée en config.

Il faut aussi penser à ajouter cette annotation à l’attribut qui porte la relation : dans notre cas l’attribut $foodBaskets de l’entité Basket.

Bien évidemment, on peut déclarer plusieurs Groups par propriété pour plus de flexibilité.

Retour d’expérience

À l’aide de toutes ses technos, l’équipe d’AppVentus a pu mettre en place très rapidement ces deux applications totalement autonomes avec :

  • un système de création de compte et d’authentification
  • une Single Page Application full AngularJS
  • une API REST documentée et Hypermedia
  • plusieurs CRUD fonctionnant avec tout type de relations

Nous allons probablement réutiliser ce système tel qu’il a été implémenté pour les projets clients qui s’y prêteront. La grande nouveauté pour l’équipe sera d’organiser ses développements de manière décorélée entre l’API et la SPA. Pour toute nouvelle feature, il faudra commencer par la conception complète et documentée de l’API avant d’attaquer le front.

Les connaissances que nous avons pu acquérir sur Schema.org vont pouvoir être mises en application sur notre DCMS Victoire qui a été pensé pour répondre aux problématiques du web sémantique. Le schema-generator utilisé dans API Platform pourra probablement nous faire gagner du temps sur ce point.

Projet sur Github

Le POC réalisé est loin d’être optimisé mais voici les sources si vous souhaitez voir plus en détail ce qui a été développé :

Team

L’équipe pour ce POC made in AppVentus :

comments powered by Disqus