Introduction

Dans les articles précédents, nous avons abordé le principe des Handlers. Leurs utilisations pour afficher de simples pages reste accessibles même pour les débutants. Cependant cela se complique un peu lorsqu’il s’agit de les imbriquer horizontalement tant pour le cerveau que pour la maintenance.

Nous allons au cours de cet article, tenter de vous éclairer et de vous simplifier leur utilisation, en créant un gestionnaire de middlewares plus souples à manipuler.

Pré-requis :

Qu’est-ce qu’un middleware ?

Un middleware est un logiciel tiers qui permet à deux applications de se mettre en relation, d’échanger de façon interopérable. Il est comme un médiateur et peut prendre des décisions selon le contexte.

Par exemple un client exécute une requête sur un serveur mais pour finaliser celle-ci, un middleware vérifiera si vous êtes bien authentifié pour vous laisser accéder aux fichiers. Un autre middleware pourrait journaliser toutes les requêtes entrantes et ou sortantes, etc.

Golang Middleware

« En théorie c’est un concept relativement simple mais qu’en est-il avec Go ? « 

— Gopher

La création de middlewares avec Go est le résultat d’un handler imbriqué dans un autre et ainsi de suite…

À l’image des poupées russes si vous souhaitez les imbriquer il faut qu’elles aient la même forme. Avec Go c’est pareil sauf que dans notre cas la forme est représentée par la signature de la méthode « ServeHTTP« .

« Tu veux surement parler de l’interface http.Handler ? »

— Gopher

Exactement ! L’interface http.Handler est une simple interface n’imposant qu’une seule méthode. Pour que la magie opère il suffit de l’implémenter.

Reprenons l’exemple ci-dessus pour le transformer en code :

Détaillons un peu ce code :

Le but de notre application est d’afficher « Hello Gopher », mais avant cela des middlewares vont venir s’interposer avant le rendu final. Chaque middleware a la responsabilité de réaliser une tâche avant de passer le relais à un autre. Une fois les tâches des middlewares effectuées la page peut alors être renvoyé vers le navigateur.

  • Ligne 10
    On donne comme argument le handler « PageFinale » au middleware AuthMiddleware qui à son tour est donné comme argument au LogMiddleware, c’est le principe du décorateur

« Super comme démo mais là on a que deux middlewares ! Et si j’en ai une dizaine à placer sur une même ligne, comment je fais pour garder un code clair et maintenable ? »

— Gopher

La configuration des middlewares à la ligne 10 est en effet très horizontale mais il est possible de la rendre plus verticale et donc plus claire pour nous simples humanoïdes :

Si on regarde de plus près on se rend compte que ça ressemble au concept des Poupées Russes.

Gopher Doll

Créez un gestionnaire de Middleware

Jusqu’à maintenant nous avons vu ce qu’est un middleware et comment le mettre en œuvre de façon standard. Dans cette partie nous allons voir comment créer un gestionnaire de middleware. En plus de simplifier la tâche, l’intérêt est d’obtenir un code plus lisible, maintenable et toujours réutilisable.

Ce qui revient le plus fréquemment lorsque l’on crée un middleware c’est une fonction qui prend en paramètre un Handler qui retourne à son tour le Handler suivant.

Nous allons créer un type nommé « Middleware » basé sur cette forme qui sera au cœur de notre gestionnaire.

Une fois notre type créé, nous ajouterons une fonction nommée « Use » qui prendra en paramètre un tableau de fonction de même type que Middleware et qui retournera aussi à son tour une fonction typée Middleware.

« Use » est une enveloppe qui contient des middlewares et une fonction de retour. Cette fonction d’une part s’alimente de ces middlewares et d’autre part de la page finale qu’elle prendra en argument lors de son exécution. L’imbrication des middlewares avec la page finale lui permet, de générer et retourner le Handler satisfaisant l’interface http.Handler nécessaire au serveur pour afficher le rendu.

« Use » est ce qu’on appelle une closure (fermeture).

Pour compléter notre code, il faut récupérer et parcourir le tableau des middlewares. L’ordre du tableau sera le suivant :

0 : LogMiddleware
1 : AuthMiddleware

Faisons la boucle manuellement pour mieux comprendre le fonctionnement :

  1. nous parcourons le tableau de façon incrémentale de 0 à 1
  2. à l’index 0 nous récupérons LogMiddleware au quel nous donnons la pageFinale
  3. à l’index 1 nous récupérons AuthMiddleware et lui fournissons LogMiddleware

Ce code est correcte mais on remarque que c’est le premier élément du tableau LogMiddleware qui prend en argument pageFinale hors nous voudrions que ce soit AuthMiddleware.

Pour le faire dans le bon ordre il suffit de parcourir le tableau de façon décrémentale en commençant par le dernier élément :

Ajoutons maintenant notre boucle pour automatiser cette tâche :

Enfin passons à l’utilisation de notre fonction :

L’imbrication est encapsulée dans notre fonction et ne sera plus visible à l’utilisation. Si le nombre de middlewares augmente, ajoutez-les sur plusieurs lignes :

Ajoutez du sucre syntaxique

Pour terminer ajoutons un peu de sucre syntaxique pour rendre notre code plus confortable à utiliser.

Nous créons cette méthode pour éviter d’avoir à caster la fonction affichant la page finale après le traitement des middlewares.

Ajoutons une méthode « ThenFunc » à notre type Middleware pour convertir une fonction de type http.HandlerFunc en http.Handler :

Pour l’utiliser, il suffit de l’invoquer, en la chaînant à la fonction « Use » :

Conclusion

La lecture du code en est simplifiée et rend l’utilisation des middlewares plus agréable. Traiter les middlewares comme un tableau offre plus de souplesse et masque la complexité de l’imbrication.

Il n'y a pas de commentaires.