Consommer une API publique en cross-domain dans un navigateur avec javascript et JSONP

Ces dernières années, le secteur du web a évolué très rapidement. Le nombre de terminaux mobiles a explosé, et les navigateurs ont vu leurs capacités augmenter radicalement. De fait, le modèle classique du serveur ne fournissant que des pages html à des browsers d’ordinateurs de bureau a décliné.

À sa place s’est développé un écosystème de services, exposant leurs données dans plusieurs formats pour une foule de clients différents.
Il incombe donc aux développeurs de ces services et de ces clients d’employer des méthodes standardisées pour établir la communication: les protocoles et les APIs.
Dans cet article, nous allons nous intéresser plus particulièrement aux navigateurs.
Grâce aux progrès du langage javascript et de ses implémentations, les navigateurs sont capables de consommer des données exposées à travers le protocole HTTP sans qu’il soit nécessaire de recharger la page sur laquelle se trouve l’utilisateur, notamment via AJAX.
On parle désormais de SPA (Single Page Application) pour qualifier ces sites qui reposent presque uniquement sur javascript pour contrôler leur interface.
Dans une application web, il est de plus en plus rare de ne pas intégrer de données provenant de services tiers: flux vidéos, modules de réseaux sociaux, de commentaires, de reviews, d’authentification… La liste est longue. Et comme celles-ci sont généralement disponibles via HTTP, cela fait sens de déplacer au maximum cette charge du serveur vers le navigateur.
Comme nous l’avons dit, javascript et AJAX permettent de faire cela. Mais AJAX a ses limitations. Il est notamment interdit d’envoyer des requêtes vers un autre domaine que celui dont est issue la page d’origine.
Pour pallier cela, différentes techniques ont vu le jour.
(Note: pour des raisons de sécurité, veillez à ne consommer de cette manière que des APIs ne nécessitant pas de placer des données sensibles en clair dans votre code)

L’utilisation d’un proxy

Il s’agit de la méthode la plus évidente: employer un proxy sur le domaine hébergeant la page, par lequel transiteront les requêtes destinées à d’autres domaines, effectuées normalement via AJAX.
Néanmoins, cette technique augmente la charge côté serveur et peut présenter un risque de sécurité (utilisation du proxy par un tiers malveillant réalisant une attaque sur le domaine cible par l’intermédiaire de votre serveur). Elle n’est de plus pas forcément facile à mettre en place.

CORS

CORS est l’acronyme de Cross Origin Resource Sharing. Il s’agit d’un protocole impliquant l’échange entre le browser et le serveur cible de requêtes possédant des headers particuliers.
Méthode la plus moderne pour pratiquer le cross domain, CORS possède de nombreux avantages, notamment une sécurité accrue et le support de plusieurs verbes HTTP.
Elle nécessite d’être implémentée à la fois par le browser et et le serveur. Si vos développements ne visent que des navigateurs implémentants les derniers standards, et si les APIs que vous voulez consommer sont accessibles via CORS, préférez cette technique.
Pour savoir quels navigateurs supportent CORS >>
Côté serveur, référez-vous à la documentation de l’API que vous désirez consommer.

JSONP

JSONP est l’acronyme de JSON with Padding. La technique, que nous allons voir plus en détail dans la suite de l’article, repose sur la possibilité laissée par les navigateurs d’inclure des scripts provenant d’un domaine différent de celui qui héberge la page courante. L’astuce consiste donc à ajouter dynamiquement une balise script au DOM, en passant votre requête comme attribut src. Cette requête doit comporter un paramètre ‘callback’ contenant le nom d’une fonction définie dans votre page. Le serveur cible, s’il supporte JSONP, vous renverra alors ses données au format JSON, mais en les enveloppant dans un appel à la fonction de callback (‘Padding’). Cette dernière sera donc exécutée, avec les données du serveur en paramètre.
L’avantage principal de cette méthode, c’est d’être utilisable sur tous les navigateurs, et d’être simple de mise en oeuvre. Elle est de plus assez largement supportée par les APIs publiques.
Elle présente toutefois plusieurs inconvénients:

  • Le serveur cible renvoie du code qui est exécuté directement sous possibilité de le pré-parser, aussi les sources de données doivent-elles être de confiance.
  • La gestion d’erreur (timeout, bad request) est moins facile qu’avec AJAX.
  • Il n’est possible d’exécuter que des requêtes de type GET.

Une implémentation simple de code client JSONP

Le code présenté ici est à visée didactique et ne doit pas être employé tel quel en production. Plusieurs bibliothèques javascript open source telles que JQuery implémentent proprement la consommation de données via JSONP et même si vous ne désirez pas les utiliser, vous pouvez en étudier le code source et en extraire les parties qui vous intéressent.

Le code de l’exemple complet est disponible sur github >>

Ceci dit, place au code.

Commençons par une simple page html comportant une balise script.

Dans cette balise, plaçons une fonction qui, lorsqu’elle sera appelée avec une url en paramètre, insèrera une balise script dans la page avec cette url en tant que valeur de l’attribut src, exécutant ainsi la requête. Au passage, nous allons mettre l’objet DOM correspondant à la balise head en cache pour ne pas devoir le récupérer depuis le DOM à chaque requête.

Nous avons là une base qui fonctionne, mais qui nous oblige à construire chaque requête JSONP à la main. Ajoutons donc quelques fonctions pour simplifier l’utilisation de l’interface.
D’abord la plus importante: à partir d’une url de base et d’un plain object, elle transformera les paires clef/valeur composant l’objet en paramètres d’url et renverra une requête complète.

Et pour finir, une fonction reposant sur le code précédent qui à partir d’une url, d’un plain object et du nom de notre fonction de callback effectuera tout le processus.

À ce stade, nous pouvons ouvrir le fichier dans un navigateur et utiliser la console pour envoyer des requêtes, mais ce n’est pas très visuel.
Essayons-nous donc à un cas pratique sur une API publique.

Exemple d’utilisation: insérer dans une page une vidéo et ses données associées, via l’api publique Vimeo

Nous allons ajouter à notre page précédente deux balises div, un bouton et quelques champs.
Les champs serviront à indiquer l’url de la vidéo ainsi que la hauteur et la largeur désirées. Au clic sur le bouton, le player vidéo sera inséré dans une div, et quelques informations dans une autre (le titre et l’auteur).
Nous utiliserons pour celà l’API oEmbed, dont la documentation est disponible ici >>
Au passage, nous allons ajouter les nouveaux éléments à notre cache d’objets DOM.

Une fois notre markup à jour, créons la fonction qui appellera l’API. Notre code contiendra l’URL de cette dernière, ainsi que le nom d’une fonction de callback (celle avec laquelle l’API effectuera le ‘padding’), qui restera à créer.

Écrivons maintenant le callback. Cette fonction doit attendre en paramètre les données récupérées.

Enfin, l’event handler pour le click sur notre bouton.

L’event handler est attaché via la propriété onclick de l’élément dans notre méthode d’init. Ceci, tout comme l’affectation de la méthode init à window.onload, est une façon obsolète de gérer les évènements. Une impémentation cross-browser de la gestion d’évènements sortirait du cadre de cet article et prendrait plus d’une centaine de lignes. Si le sujet vous intéresse, vous pouvez par exemple vous référer à ce document.

L’exemple est maintenant complet. Si vous ouvrez la page et remplissez les champs, comme ici:

Au click, vous obtiendrez ceci:

Lorsque vous cliquez sur le bouton, vous pouvez utiliser l’onglet réseau de Firebug pour inspecter la requête et la réponse. Vous pourrez ainsi voir le JSONP renvoyé.

Nous voici arrivés à la fin de cet article, qui je l’espère vous aura permis de mieux comprendre ce qu’est JSONP et comment l’utiliser. Il ne tient maintenant qu’à vous d’être créatifs et d’aller plus loin. Joyeux coding !

 FennNaten
Mordu de développement web, je suis toujours prêt à relever un nouveau challenge. J’aime par-dessus tout apprendre de nouvelles choses, quelque soit le sujet, et c’est un plaisir de pouvoir partager les connaissances accumulées.
Lorsque je ne suis pas devant mon clavier, on pourra me trouver dans un pub avec des amis, autour d’une table de jeu de rôle ou de plateau, dans un salon de l’imaginaire tel que les Utopiales, ou encore n’importe où, le nez dans un bouquin.

________________________________________
Ma / mes techno(s) de prédilection : C#, ASP.NET MVC, javascript
Le site incontournable : Hacker News
Une devise : Espère le meilleur, prépare-toi au pire
Où me contacter : sur LinkedIn

Retrouvez tous ses articles >>

Fenn Naten

Recent Posts

Communauté Tech et féminine : Interview avec Helvira de Motiv’her

Elles sont passées où les femmes dans la tech ? Entre le manque de représentation…

3 jours ago

Consommer des APIs HTTP en PHP comme un pro avec Nicolas Grekas.

Dans cette vidéo, on interview Nicolas Grekas, contributeur clé de Symfony, pour discuter de sa…

3 jours ago

Trouver son job grâce à WeLoveDevs.

 Comment trouver son job dans la tech ? Marie a la réponse ! Grâce à…

5 jours ago

Adobe, L’empire créatif.

Adobe, l'empire créatif, et pas des moindres ! Belle ascension de la part de ces…

1 semaine ago

La MAO musique ou musique assistée par ordinateur

Est-ce plus simple de créer des morceaux avec les outils de Musique Assistée par Ordinateur…

1 semaine ago