Zend Framework

Utilisation de Zend REST : Partie 1

Bonjour, aujourd’hui nous allons voir comment créer un service REST avec Zend et comment signaler à Zend que nous attendons la réponse dans le format JSON.

Ce tutoriel n’est que le premier d’une série d’autres tutoriels permettant d’aller plus loin dans Zend REST à savoir :

  • Présentation de REST et configuration de Zend
  • Utilisation d’une APIKEY et des différentes méthodes HTTP
  • Utilisation de notre service REST à partir d’Android

Comme vous devez vous en douter, aujourd’hui nous allons attaquer Présentation de REST et configuration de Zend.

I- Présentation de REST :

Et nous allons commencer par une petite définition Wikipedia de ce qu’est un service REST :

REST (Representational State Transfer) est une manière de construire une application pour les systèmes distribués comme le World Wide Web.

L’application de cette architecture au Web se comprend sur quelques principes simples :

  • l’URI est important : connaître l’URI doit suffire pour nommer et identifier une ressource
  • HTTP fournit toutes les opérations nécessaires (GET, POST, PUT et DELETE, essentiellement) 
  • chaque opération est auto-suffisante : il n’y a pas d’état ;
  • utilisation des standards hypermedia : HTML ou XML qui permettent de faire des liens vers d’autres ressources et d’assurer ainsi la navigation dans l’application REST sont souvent utilisés. Néanmoins, l’utilisation d’autres formats comme JSON ou autres est possible.

Nous allons donc utiliser cette architecture afin de, au final, proposer un service Web pour une application Android. En fonction des choses demandées par notre application, nous effectuerons l’une des requêtes http existantes (GET, PUT, POST, DELETE) afin d’accéder à l’une de nos actions. Lorsqu’une action est effectuée, notre application recevra une réponse au format JSON.

II- Configuration de votre projet Zend :

Je pars du principe que vous avez un projet Zend existant et modulaire. Si vous n’avez pas cela, je vous invite à suivre ma suite de tutoriels sur Zend : Introduction au Framework Zend – Partie 1.

Nous allons placer toute la partie REST dans un module du même nom et nous allons créer le controller TutoController :

class Rest_TutoController extends Zend_Rest_Controller
{
    public function init(){
        $bootstrap = $this->getInvokeArg('bootstrap');
        $options = $bootstrap->getOption('resources');

        $contextSwitch = $this->_helper->getHelper('contextSwitch');
        $contextSwitch  ->addActionContext('index', array('json'))
                        ->addActionContext('get', array("json"))
                        ->addActionContext('post', array("json"))
                        ->addActionContext('put', array("json"))
                        ->addActionContext('delete', array("json"))
                        ->initContext('json');
    }

    public function deleteAction() {
        $this->view->retour = "deleteAction";
    }

    public function getAction() {
        $this->view->retour = "getAction";
    }

    public function indexAction() {
        $this->view->retour = "indexAction";
    }

    public function postAction() {
        $this->view->retour = "postAction";
    }

    public function putAction() {
        $this->view->retour = "putAction";
    }
}

Comme vous pouvez le voir, notre Controller n’étend pas du tout de Zend_Controller_Action mais de Zend_Rest_Controller. Ce controller marche pareil que Zend_Controller_Action à la différence près qu’il implémente chaque action utile à chaque requête HTTP.

Faire ce controller ne suffit pas à faire que Zend_Rest marche. Normalement, en saisissant simplement l’adresse suivante : http://votresite/rest/tuto et en fonction de la requête que vous avez (POST, …) vous devez tomber automatiquement sur l’action associée. Pour que Zend fasse justement le routage adéquat, nous devons le lui signaler dans le Bootstrap principal :

protected function _initRestRoute()
{
    $this->bootstrap('Request');
    $front = $this->getResource('FrontController');
    $restRoute = new Zend_Rest_Route($front, array(), array(
        'rest' => array(
                    'tuto',
                  )
    ));
    $front->getRouter()->addRoute('routerest', $restRoute);
}  

Comme vous pouvez le voir, on demande de charger la fonction initRequest de notre Bootstrap grâce à la commande 

$this->bootstrap('Request');

Et si vous essayez d’accéder à votre site, vous devriez avoir l’erreur suivante si vous n’avez pas défini la fonction initRequest :

Fatal error: Uncaught exception 'Zend_Application_Bootstrap_Exception' with message 'Resource matching "Request" not found' in ...

Pour remédier à cela, voici une la fonction initRequest que j’utilise, elle me permet d’avoir tout le temps un objet Zend_Controller_Request_Http dans mon entité $this->_request de mes controllers :

protected function _initRequest()
{
    $this->bootstrap('FrontController');
    $front = $this->getResource('FrontController');
    $request = $front->getRequest();
    if (null === $front->getRequest()) {
        $request = new Zend_Controller_Request_Http();
        $front->setRequest($request);
    }
    return $request;        
}

Bien, maintenant toute la configuration dite, de base, a été faite. Maintenant, si vous essayez d’accéder à votre action index (appelée par défaut si aucun paramètre GET et si requête de type GET), vous devriez avoir une erreur typique de vue non existante sur votre serveur. C’est normal, nous allons justement voir comment obliger un retour JSON grâce aux Contextes.

III – Les Contextes :

Afin d’expliquer ce que sont les contextes, je vous invite à lire le paragraphe associé dans la documentation Zend :

Les Contextes sont des conditions de formatage pour une ou plusieurs requêtes en fonction de leur type (requête AJAX ou non) le retour des actions appelées. Zend fournit deux aides d’action afin de nous simplifier la tâche : ContextSwitch et AjaxContext. Voici ce que nous dit justement la documentation Zend :

L’aide d’action ContextSwitch est destinée à faciliter le retour de différents formats de réponse à une requête.L’AjaxContext est une aide spécialisée de ContextSwitch qui permet le renvoi de réponses à XmlHttpRequest.

Pour l’activer, vous devez indiquer à votre contrôleur quelles actions répondent à quel contexte. Si une requête d’entrée indique un contexte valide pour une action, alors l’aide d’action en charge :

  • Va désactiver les layouts, si elles sont activées.
  • Va changer le suffixe de la vue à rendre, il faudra donc créer une vue par contexte.
  • Va envoyer les bons en-têtes de réponse en fonction du contexte désiré.
  • Va éventuellement en option appeler des fonctions pour configurer le contexte, ou des fonctions de post-processing.

Normalement, nous devons signaler dans l’url le format de retour de la requête entre JSON et XML de la façon suivante : /module/controller/action//format/<json|xml>. Je vais vous montrer comment configurer nos Contextes pour qu’ils prennent toujours le format JSON par défaut.

Vu que nous allons requêter directement via une application Android (et notre navigateur pour les tests de départ), nous allons utiliser l’aide de vue ContextSwitch. AjaxContext ne nous sert à rien ici car il regarde si la requête est une requête AJAX pour utiliser les contextes alors que ContextSwitch le fait tout le temps.

Pour ce faire, nous allons définir tout ceci dans la fonction init() de notre controller de la façon suivante :

public function init(){
    $bootstrap = $this->getInvokeArg('bootstrap');
    $options = $bootstrap->getOption('resources');

    $contextSwitch = $this->_helper->getHelper('contextSwitch');
    $contextSwitch  ->addActionContext('index', array('json'))
                    ->addActionContext('get', array("json"))
                    ->addActionContext('post', array("json"))
                    ->addActionContext('put', array("json"))
                    ->addActionContext('delete', array("json"))
                    ->initContext('json');
}

La seule contrainte de ces aides de vue, c’est qu’il faut renseigner les formats possibles pour chaque action concernée grâce à la fonction addActionContext() et nous définissons le format choisi par défaut grâce à initContext().

Maintenant, si vous allez sur votre site http://votresite/rest/tuto vous devriez avoir la réponse suivante au format JSON :

{"retour":"indexAction"}

En fonction de votre navigateur il vous sera demandé soit de télécharger un fichier JSON, soit le résultat sera affiché directement dedans.

Le retour JSON n’est qu’une sérialisation PHP vers JSON de toutes vos variables de vues. Si vous avez des tableaux, ils seront convertis en tableau JSON, des objets PHP : en objet JSON si c’est possible. Pour plus d’information, regardez comment marche Zend_JSON_Encode car c’est basé dessus.

Conclusion de la partie 1 :

Voilà, ici nous avons pu voir comment utiliser les contextes, configurer Zend pour REST. Vous pouvez dès maintenant créer une application Zend basique utilisant les contextes. Mais pour ce qui est de REST, il nous manque à voir les différentes requêtes HTTP ainsi que l’utilisation d’une APIKEY pour sécuriser à minima tout ça. Mais pour ceci, nous le verrons dans le prochain tutoriel. 

Sur ce, je vous souhaite de bonnes fêtes de fin d’année et surtout, profitez bien.