17.2 Middleware

Les middlewares permettent de modifier le comportement d'une route enregistrée. Un middleware permet d'exécuter un code spécifique avant ou après l'éxécution du code de la route.

Les middlewares exécutés avant le code de la route ne peuvent pas modifier les données retournés par la route. Ils peuvent ajouter des messages ou modifier les entêtes HTTP de la réponse.

Les middlewares exécutés après le code de la route peuvent en plus modifier les données retournées.

17.2.1 Enregistrement d'un middleware

Le principe d'enregistrement d'un middleware est identique à celui de l'enregistrement d'une route.

La différence est que le fichier json de description doit être placé dans le répertoire HTTPAPI_V1/rules.d/middleware.d.

[
     {
         "order" :        300,
         "process":       "before"
         "class" :        "\\My\\Message",
         "regExp" :       "%^/documents/?(?P<identifier>[^/\\.]+)%",
         "description" :  "Add message",
         "canonicalURL" : "documents/<documentId>"
     },
     {
         "order" :        100,
         "process":       "after"
         "class" :        "\\My\\SayHello",
         "regExp" :       "%^/documents/?(?P<identifier>[^/\\.]+)$%",
         "description" :  "Say Hello World",
         "canonicalURL" : "documents/"
     },
     {
         "order" :        1000,
         "process":       "before"
         "class" :        "\\My\\Always",
         "regExp" :       "%%",
         "description" :  "Always do process",
         "canonicalURL" : "*"
     }
]

La clef process doit être indiquée. La valeur before indique que le middleware est exécuté avant la route. La valeur after indique que le middleware est exécuté après la route.

Tous les middlewares dont la rexExp correspond à l'url sont exécutés. L'ordre est donné par la clef order. L'ordre d'exécution est du plus grand au plus petit.

Les middlewares exécutés pour une requête sont indiqués dans les headers de la réponse http avec le mot-clef "X-Dcp-Middleware". La description du middleware est utilisé comme valeur de cet header.

17.2.2 Classe de middlewares

La clef class indique la classe de middleware qui doit être exécutée. Cette classe doit hériter de la classe Dcp\HttpApi\V1\Crud\MiddleWare.

Suivant la méthode de la requête http, les méthodes suivantes sont exécutées :

HTTP Method Middleware method
GET void ::read($identifier)
POST void ::create()
PUT void ::update($identifier)
DELETE void ::delete($identifier)

La variable $identifier correspond à la valeur du paramètre "identifier" présent dans l'expression régulière (regexp) de la déclaration. Le retour de ces méthodes n'est pas utilisé.

La classe de Middleware dispose de 2 méthodes pour consulter les informations sur la requête et pour manipuler la réponse.

17.2.2.1 getHttpRequest

La méthode getHttpRequest() retourne un objet Dcp\HttpApi\V1\Api\HttpRequest.

Cet objet permet d'accéder aux éléments de la requête reçue.

  • string getMethod() : retourne la méthode de la requête GET, POST, PUT , DELETE
  • array getHeaders : retourne la liste des entêtes HTTP reçus
  • array getQuery() : retourne les variables de la requête (voir contentParameters)
  • array getUri() : retourne la composition de l'url (idem parse_url)

17.2.2.2 getHttpResponse

La méthode getHttpResponse() retourne un objet Dcp\HttpApi\V1\Api\HttpResponse.

Cet objet permet d'accéder aux éléments de la réponse en cours et permet la modification de celle-ci.

Méthodes d'accès : (getter)

  • mixed getBody() : retourne les données (partie data )à envoyer
  • mixed getResponse() : retourne les données personnalisées à envoyer (retourne la valeur donnée par setResponse()).
  • string getStatusHeader() : retourne le statut http à envoyer
  • string[] getHeaders() : retourne la liste des headers http à envoyer
  • RecordReturnMessage getMessages() : retourne la liste des messages à envoyer

Méthodes de modification : (setter)

  • addMessage(RecordReturnMessage $message) : ajouter un messages
  • setStatusHeader($httpStatusHeader) : modifier le status HTTP
  • addHeader($key, $value, $replace = true) : ajouter un header http
  • setBody($data) : modifie les données (partie data de la réponse) à renvoyer
  • setResponse($response) : modifie la réponse complète - Écrase la partie data.
  • sendResponse() : donne l'ordre d'envoi de la réponse, les traitements suivants (autres middlewares ou code principal) sont ignorés.

L'objet retourné par la méthode ::getHttpResponse() est le même pour tous les middlewares. Le middleware suivant accède à la réponse du middleware précédent.

Attention : l'appel de la route principale écrase les éventuelles affectations effectuées par les middlewares "before" au moyen des méthodes setBody, setResponse et setStatusHeader.

Lorsque le contenu est de la donnée json, les méthodes getBody et setBody manipulent la partie data fournie par les méthodes CRUD.

Pour retourner des données personnalisées, il faut utiliser la méthode setResponse(). Lorsque cette méthode est utilisée, les messages et la partie data ne sont pas transmises dans le message. Pour les inclure, il faut explicitement les ajouter.

$httpResponse->setResponse([
             "data"=>$httpResponse->getBody(),
             "messages"=>$httpResponse->getMessages(),
             "myCustom"=> $myCustomValues
]);

Lorsque le contenu est du HTML, ces méthodes manipulent directement la chaîne de caractères correspondant au code HTML.

17.2.2.3 Exemple

Ajout d'un message dans un middleware "before".

namespace My;
 
use Dcp\HttpApi\V1\Crud\MiddleWare;
use Dcp\HttpApi\V1\DocManager\DocManager as DocManager;
use Dcp\HttpApi\V1\Api\RecordReturnMessage;
 
class Message extends MiddleWare
{
    public function read($resourceId)
    {
        $document=DocManager::getDocument($resourceId);
 
        if ($document) {
            $message=new RecordReturnMessage();
            $message->contentText=sprintf("Loading %s - %s", 
                                            $document->getTitle(), 
                                            date("Y-m-d"));
            $this->getHttpResponse()->addMessage($message);
        }
    }
}

Ajout d'un champ "myCustom" dans la réponse d'un middleware "after".

namespace My;
 
use Dcp\HttpApi\V1\Crud\MiddleWare;
use Dcp\HttpApi\V1\DocManager\DocManager as DocManager;
use Dcp\HttpApi\V1\Api\RecordReturnMessage;
 
class SayHello extends MiddleWare
{
    public function read($resourceId)
    {
        $document=DocManager::getDocument($resourceId);
 
        if ($document) {
            $httpResponse=$this->getHttpResponse();
            $response=$httpResponse->getBody();
            if (is_array($response)) {
                $response["myCustom"] = "Hello world";
                $httpResponse->setBody($response);
            } 
        }
    }
}

Le retour sera de la forme :

{
    "success":true,
    "messages":[
        {"type":"message",
        "contentText":"Loading Testing - 2017-03-15"}],
    "data":{
        "uri":"\/api\/v1\/documents\/35699\/locks\/permanent",
        "lock":null,
        "myCustom":"Hello world"}
    }
}

Construction d'une réponse personnalisée "myCustom" dans la réponse d'un middleware "after".

namespace My;
 
use Dcp\HttpApi\V1\Crud\MiddleWare;
use Dcp\HttpApi\V1\DocManager\DocManager as DocManager;
use Dcp\HttpApi\V1\Api\RecordReturnMessage;
 
class SayCustomHello extends MiddleWare
{
    public function read($resourceId)
    {
        $document=DocManager::getDocument($resourceId);
 
        if ($document) {
            $httpResponse=$this->getHttpResponse();
            $body=$httpResponse->getBody();
            if (is_array($body)) {
                $response["myCustom"] = "Hello world";
                $response["myData"] = $body;
                $httpResponse->setResponse($response);
            } 
        }
    }
}
Le retour sera de la forme :
{
    "myCustom":"Hello world",
    "myData":{
        "uri":"\/api\/v1\/documents\/35699\/locks\/permanent",
        "lock":null}
    }
}
×