• 50 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 29/07/2019

Communiquez avec d'autres APIs

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Il n'est pas rare qu'en développant une API, vous ayez besoin de communiquer avec d'autres APIs ! Instagram, Twitter, Facebook, Github… Les réseaux sociaux sont souvent les APIs dont nous avons rapidement besoin (pour la gestion d'utilisateurs par exemple).

La communication avec d'autres applications peut être encore plus complexe. Voici un exemple :

 

Communication entre plusieurs applications
Communication entre plusieurs applications

Les applications avec lesquelles vous souhaitez communiquer peuvent être déjà existantes, comme être écrites par vous (ou votre équipe). Ce genre d'architecture est dite "Orientée Service" (SOA - Service Oriented Architecture). Peut-être avez-vous également entendu parlé de microservices ? C'est une manière d'architecturer son application au global : il s'agit de créer une application par domaine métier (gestion d'utilisateurs, d'articles, de produits…). Cela demande à ce que les applications communiquent entre elles pour échanger des informations.

Ceci dit, cela pose quelques problématiques qu'il ne faut pas ignorer :

  • le fait de démultiplier le nombre d'applications demande une maintenance qui ajoute de la complexité à votre travail, puisqu'il faut se soucier de la compatibilité descendante (backward compatibility break ou BC Break) ;

  • plus il y a d'applications à contacter, plus le temps de réponse total augmente ;

  • la gestion des bugs dans une seule application peut être complexe, lorsque cette application dépend d'autres applications, les tests d'intégration ne sont pas facilités, bien au contraire !

Réfléchissez-y à deux fois avant de vous lancer dans ce type d'architecture ! ;)

Communiquer avec une API existante

Voyons comment interroger une API météo pour récupérer la météo courante.

Pour ce faire, nous allons utiliser la librairie Guzzle, permettant d'effectuer des requêtes HTTP très simplement.

Installation du CSAGuzzleBundle

Le CSAGuzzleBundle facilite l'intégration de la librairie Guzzle. Commençons par installer le bundle avec la commande suivante :

$ composer require csa/guzzle-bundle
Installation du CSAGuzzleBundle
Installation du CSAGuzzleBundle

Puis il faut déclarer le bundle dans la classe  AppBundle:

<?php

use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = [
            // …
            new Csa\Bundle\GuzzleBundle\CsaGuzzleBundle(),
        ];

        // …

        return $bundles;
    }
}

Utilisation de base

 Je vous propose d'appeler une API pour récupérer la météo courante : l'API que nous allons appeler est celle du site openweathermap.

Étape 1 : créer un client HTTP

Il s'agit d'effectuer une requête HTTP en GET avec notre API Rest. Pour effectuer une requête, il nous faut un client HTTP. Pour le créer, il faut ajouter la configuration suivante :

# app/config/config.yml

csa_guzzle:
    clients:
        weather:
            config:
                base_uri: http://api.openweathermap.org

 Comme vous pouvez le constater, la configuration est très simple ! 

La configuration ci-dessus induit une création automatique  de service par le CSAGuzzleBundle, qui nous servira pour exécuter une requête HTTP : sous la clé de configurationcsa_guzzle.clients, il suffit d'ajouter un nom (celui de votre choix), qui conditionnera le nom du service généré. Puis, il faut indiquer l'URI de base (http://api.openweathermap.org) que l'on complètera lors de la requête HTTP.

Étape 2 : Créer le service en charge d'effectuer la requête HTTP à l'API

Créons un dossier Weather dans le dossier src/AppBundle. Dans ce dossier, créons la classeWeatheravec le code suivant :

<?php

namespace AppBundle\Weather;

use GuzzleHttp\Client;
use JMS\Serializer\Serializer;

class Weather
{
    private $weatherClient;
    private $serializer;
    private $apiKey;

    public function __construct(Client $weatherClient, Serializer $serializer, $apiKey)
    {
        $this->weatherClient = $weatherClient;
        $this->serializer = $serializer;
        $this->apiKey = $apiKey;
    }

    public function getCurrent()
    {
        $uri = '/data/2.5/weather?q=Paris&APPID='.$this->apiKey;
        $response = $this->weatherClient->get($uri);

        $data = $this->serializer->deserialize($response->getBody()->getContents(), 'array', 'json');

        return [
            'city' => $data['name'],
            'description' => $data['weather'][0]['main']
        ];
    }
}

Cette classe représente le service en charge de la récupération des informations que nous allons présenter à notre utilisateur.

Il nous faut le déclarer en tant que service. Il faut donc ouvrir le fichierservices.yml, dans le dossierapp/configet y ajouter les lignes suivantes :

#app/config/services.yml

services:
    # …
    app.weather:
        class: AppBundle\Weather\Weather
        arguments:
            - '@csa_guzzle.client.weather'
            - '@jms_serializer'
            - %weather_api_key%

Afin de permettre le changement de la clé d'API facilement en fonction des installations de l'application, j'ai choisi de mettre la clé en paramètre. Il faut donc créer et renseigner le paramètreweather_api_keycontenant la clé d'api :

# app/config/parameters.yml

parameters:
    # …
    weather_api_key: 04f3ecaa61866ac151eee1a4af5b22c1

Les arguments que nous injectons à notre serviceapp.weathersont les suivants : 

  1. le service csa_guzzle.client.weathercorrespond au service généré par le CSAGuzzleBundle, suite à la configuration que nous venons d'ajouter. Ce service est le client HTTP que nous allons pouvoir utiliser pour forger une requête HTTP. Nous l'utilisons à la ligne 24 de la classeWeather.

  2. le servicejms_serializernous servira à déserialiser les données reçues de l'API OpenWeatherMap.

  3. le paramètreweather_api_keyest le paramètre contenant la clé d'API créée pour requêter l'API OpenweatherMap.

Le but est de construire un tableau PHP de la forme suivante :

[
    'weather => [
        'city' => 'Paris',
        'description' => 'Sunny'
    ]
]

 Ainsi, nous commençons par construire l'URI qui va nous servir à requêter l'API : en effet, le fait d'avoir créé la configuration sous la clé csa_guzzle.clients.weather.config.base_uripermet de créer un genre de préfixe à toutes les requêtes que nous effectuerons avec ce service.

Pour effectuer la requête GET, il suffit d'appeler la méthodeget()sur le service csa_guzzle.client.weatheravec le reste de l'URI que l'on souhaite appeler.

Pour accéder au contenu de la réponse, il faut récupérer une chaîne de caractères : ce qui est reçu est une réponse streamée. Pour convertir la réponse, il suffit d'écrire : $response->getBody()->getContents().

Il ne nous reste plus qu'à construire notre tableau avec les informations qui nous intéresse.

Étape 3 : Ajouter les informations météo à chaque fois que l'on récupère les informations d'un article

Comme nous  l'avons vu au chapitre "Rendez votre API auto découvrable (dernier niveau du modèle de maturité de Richardson)", lorsque nous respectons le niveau 3, il est possible d'ajouter d'autres informations liées à la ressource. Nous allons utiliser le BazingaHateoasBundle pour ajouter ces informations dans l'élément  _embedded  de l'objet JSON.

Ouvrons la classeArticlepour ajouter l'annotation suivante :

<?php

namespace AppBundle\Entity;

use Hateoas\Configuration\Annotation as Hateoas;
// …

/**
 * …
 * @Hateoas\Relation(
 *     "weather",
 *     embedded = @Hateoas\Embedded("expr(service('app.weather').getCurrent())")
 * )
 *
 */
class Article
{
}

Nous ajoutons donc l'élément   weather  à l'objet jsonArticleet nous appelons le serviceapp.weatherque nous avons créé.

Et voilà ! Voyons un  peu le résultat avec Postman :

Ajout de la météo
Ajout de la météo aux informations de l'article

Quelques aspects à ne pas négliger

Gestion d'erreur

Un aspect important à prendre en compte lorsque son application communique avec d'autres services (API), est la gestion d'erreur : en effet, il faut gérer le cas où le service appelé ne répond pas ou dans le cas où une erreur est renvoyée. Votre API doit toujours être en mesure d'offrir un service stable à vos utilisateurs, sans quoi vous risquez de les perdre…

Dans notre exemple, vous pourriez faire en sorte de renvoyer un tableau avec un message du type "Les informations ne  sont pas disponibles pour le moment". Le code pourrait donc ressembler à cela :

<?php

namespace AppBundle\Weather;

use GuzzleHttp\Client;
use JMS\Serializer\Serializer;

class Weather
{
    private $weatherClient;
    private $serializer;
    private $apiKey;

    public function __construct(Client $weatherClient, Serializer $serializer, $apiKey)
    {
        $this->weatherClient = $weatherClient;
        $this->serializer = $serializer;
        $this->apiKey = $apiKey;
    }

    public function getCurrent()
    {
        $uri = '/data/2.5/weather?q=Paris&APPID='.$this->apiKey;
        
        try {
            $response = $this->weatherClient->get($uri);
        } catch (\Exception $e) {
            // Penser à logger l'erreur.
            
            return ['error' => 'Les informations ne sont pas disponibles pour le moment.'];
        }
        

        $data = $this->serializer->deserialize($response->getBody()->getContents(), 'array', 'json');

        return [
            'city' => $data['name'],
            'description' => $data['weather'][0]['main']
        ];
    }
}

Je n'ai ajouté qu'un bloc try catch et je retourne un tableau avec le message d'erreur explicite.

Prendre en compte le temps d'appel à d'autres services

Plus votre application fait appel à des services externes, plus vous prenez le risque de rendre votre service plus lent. Multiplier les appels peut poser problème avec le temps, gardez-le en tête lors de vos choix techniques.

 

Je vous invite à lire la documentation officielle de la librairie Guzzle, ainsi que celle du bundleCSAGuzzleBundle pour vous enquérir de tout ce qui est possible de faire. Prenez soin de vérifier la version de la librairie que vous souhaitez utiliser.

 

Rendez-vous au prochain chapitre pour ajouter une nouvelle corde à notre arc : implémenter une authentification et une autorisation pour notre API de gestion d'articles. :D

Exemple de certificat de réussite
Exemple de certificat de réussite