• 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Itération 12 : ajout d'une API JSON

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

Le but de cette itération est d'intégrer à l'application une API utilisant le format JSON.

Fonctionnalités de l'API

Une API(Application Programming Interface) est une interface offerte par une application à destination d'autres applications. Une API exposée via le protocole HTTP(S) est appelée un service web

Ces dernières années, le format JSON(JavaScript Object Notation) a détroné XML et s'est imposé comme le nouveau standard pour les échanges de données entre applications via des services web.

Nous allons ajouter à notre application une API offrant les fonctionnalités suivantes :

  • consultation de la liste des articles ;

  • consultation d'un article à partir de son identifiant ;

  • ajout d'un nouvel article ;

  • suppression d'un article.

Création de l'API de consultation

Notre application offre déjà, via les classes DAO, les services d'accès aux données nécessaires. Il ne nous reste qu'à exposer ces services via JSON. Pour cela, ajoutez les lignes ci-dessous à la fin du fichierapp/routes.php.

 

<?php

// ...

// API : get all articles
$app->get('/api/articles', function() use ($app) {
    $articles = $app['dao.article']->findAll();
    // Convert an array of objects ($articles) into an array of associative arrays ($responseData)
    $responseData = array();
    foreach ($articles as $article) {
        $responseData[] = array(
            'id' => $article->getId(),
            'title' => $article->getTitle(),
            'content' => $article->getContent()
            );
    }
    // Create and return a JSON response
    return $app->json($responseData);
})->bind('api_articles');

// API : get an article
$app->get('/api/article/{id}', function($id) use ($app) {
    $article = $app['dao.article']->find($id);
    // Convert an object ($article) into an associative array ($responseData)
    $responseData = array(
        'id' => $article->getId(),
        'title' => $article->getTitle(),
        'content' => $article->getContent()
        );
    // Create and return a JSON response
    return $app->json($responseData);
})->bind('api_article');

On définit ici les contrôleurs associés aux routes/api/articles et/api/article/{id}. Ces deux contrôleurs fonctionnent de manière similaire : ils utilisent le service d'accès aux articles pour récupérer les données nécessaires, puis convertissent ces données sous forme de tableaux associatifs champs/valeurs. Enfin, ils utilisent la méthode Silex $app->json pour renvoyer la réponse au format JSON.

Essayons sans tarder de vérifier si notre API fonctionne. Pour cela, il suffit d'envoyer une requête HTTP vers l'URL http://microcms/api/articles puis d'examiner la réponse reçue.

Nous constatons que les données sont bien renvoyées. Pour obtenir une meilleure présentation du résultat, je vous conseille d'installer une extension de navigateur comme par exemple RESTClient pour Mozilla Firefox.

Une fois cette extension installée, on peut l'utiliser pour envoyer une requête HTTP GET vers http://microcms/api/articles et analyser en détail le résultat.

Les en-têtes de la réponse HTTP indiquent un succès de la requête (code 200) ainsi que le format de la réponse :application/json.

Les données reçues correspondent aux articles contenus dans notre base de données.

Création de l'API de modification

Pour créer l'API de modification (création et suppression d'un article), ajoutez les lignes suivantes à la fin du fichierapp/routes.php.

<?php

// ...

// API : create a new article
$app->post('/api/article', function(Request $request) use ($app) {
    // Check request parameters
    if (!$request->request->has('title')) {
        return $app->json('Missing required parameter: title', 400);
    }
    if (!$request->request->has('content')) {
        return $app->json('Missing required parameter: content', 400);
    }
    // Build and save the new article
    $article = new Article();
    $article->setTitle($request->request->get('title'));
    $article->setContent($request->request->get('content'));
    $app['dao.article']->save($article);
    // Convert an object ($article) into an associative array ($responseData)
    $responseData = array(
        'id' => $article->getId(),
        'title' => $article->getTitle(),
        'content' => $article->getContent()
        );
    return $app->json($responseData, 201);  // 201 = Created
})->bind('api_article_add');

// API : delete an existing article
$app->delete('/api/article/{id}', function ($id, Request $request) use ($app) {
    // Delete all associated comments
    $app['dao.comment']->deleteAllByArticle($id);
    // Delete the article
    $app['dao.article']->delete($id);
    return $app->json('No Content', 204);  // 204 = No content
})->bind('api_article_delete');

Le premier contrôleur répond à une requête HTTP POST vers la route/api/article. Il construit un nouvel objet de la classeArticle à partir des champstitle etcontent extraits de la requête HTTP. Le nouvel article est sauvegardé dans la base de données puis renvoyé comme résultat JSON de la requête.

La second contrôleur répond à une requête HTTP DELETE vers la route/api/article/{id}. Il supprime l'article associé par l'identifiant présent dans l'URL de la requête puis renvoie une réponse indiquant que l'article n'existe plus.

Pour pouvoir créer un nouvel article en utilisant la nouvelle API de création, il faut envoyer une requête HTTP POST contenant les données de l'article (titre et contenu) au format JSON. Voici un exemple de contenu JSON.

{ 
    "title": "Another article", 
    "content": "This article was created using the JSON API. How cool is that?"
}

Le contenu JSON reçu doit être décodé avant de pouvoir être exploité dans le contrôleur. Pour cela, ajoutez les lignes ci-dessous au fichierapp/app.php.

<?php

// ...
use Symfony\Component\HttpFoundation\Request;

// ...

// Register JSON data decoder for JSON requests
$app->before(function (Request $request) {
    if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
        $data = json_decode($request->getContent(), true);
        $request->request->replace(is_array($data) ? $data : array());
    }
});

 

Ce code intercepte toutes les requêtes reçues et, si son contenu est au format JSON, décode ce contenu et la définit comme paramètres de la requête. Ainsi, les méthodes$request->request->get('title') et$request->request->get('content') de notre contrôleur permettront d'accéder aux données JSON.

Il est temps de tester notre nouvelle API. Avant d'envoyer des requêtes avec RESTClient, il faut paramétrer l'extension pour définirapplication/json comme format des données envoyées. Pour cela, allez dans le menu Headers et choisissez l'option Custom Header.

Définition du format des requêtes envoyées avec RESTClient
Définition du format des requêtes envoyées avec RESTClient

Ensuite, envoyez vers http://microcms/api/article une requête HTTP POST dont le corps (body) correspond au contenu JSON défini plus haut.

Le serveur renvoie une réponse avec le code HTTP 201, indiquant le succès de la création. Le corps de la réponse contient les données du nouvel article : son identifiant (ici : 4) a été défini au moment de l'insertion dans la base de données.‌

On peut vérifier en accédant à http://microcms avec un navigateur que le nouvel article est présent.

Enfin, vérifions que notre API de suppression fonctionne en envoyant la requête HTTP DELETE vers l'URL http://microcms/api/article/4.

Le code 204 de la réponse HTTP indique que l'élément en question n'existe plus. On le vérifie également en accédant à http://microcms.

Mise à jour des tests fonctionnels

Enfin, il faut penser à mettre à jour nos tests fonctionnels pour ajouter les URL/api/articles et/api/article/1 permettant de tester nos API de consultation. Voici la nouvelle définition de la méthodeprovideUrls de la classeAppTest, située dans le fichiertests/MicroCMS/Tests/AppTest.php.

<?php

// ...

class AppTest extends WebTestCase {
    
    // ...
    
    /**
     * Provides all valid application URLs.
     *
     * @return array The list of all valid application URLs.
     */
    public function provideUrls()
    {
        return array(
            array('/'),
            array('/article/1'),
            array('/login'),
            array('/admin'),
            array('/admin/article/add'),
            array('/admin/article/1/edit'),
            array('/admin/comment/1/edit'),
            array('/admin/user/add'),
            array('/admin/user/1/edit'),
            array('/api/articles'),
            array('/api/article/1'),
            ); 
    }
}

L'exécution des tests nous prouve que l'application fonctionne toujours correctement.

Le code source associé à cette itération est disponible sur une branche du dépôt GitHub

Bilan

Au cours de cette itération, nous avons découvert comment exposer certaines fonctionnalités de notre application aux développeurs extérieurs par le biais d'une API utilisant le format JSON. L'ajout de cette API a été facilitée par l'existence des services d'accès aux données (DAO) nécessaires, et le support du format JSON par Silex.

La prochaine itération va introduire ce qui sera l'architecture finale de notre application.

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