{"id":1499,"date":"2020-08-19T18:51:16","date_gmt":"2020-08-19T16:51:16","guid":{"rendered":"http:\/\/blogperso.union31.fr\/?p=1499"},"modified":"2020-08-22T10:10:25","modified_gmt":"2020-08-22T08:10:25","slug":"node-js-modules-externes","status":"publish","type":"post","link":"https:\/\/blogperso.union31.fr\/?p=1499","title":{"rendered":"Node.js : modules externes Express et EJS (routing et template)"},"content":{"rendered":"\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Sommaire<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#I_Introduction_aux_modules_Express_et_Ejs\" >I Introduction aux modules Express et Ejs<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#I1_Presentation\" >I.1 Pr\u00e9sentation<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#I2_Installation_dExpress_et_dEjs\" >I.2 Installation d&rsquo;Express et d&rsquo;Ejs<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#I3_Hello_Word\" >I.3 Hello Word<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#I4_Hello_Word_avec_template_Ejs\" >I.4 Hello Word avec template Ejs<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II_Module_Express\" >II Module Express<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II1_Application\" >II.1 Application<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II2_Request_et_Response\" >II.2 Request et Response<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II3_Exemple\" >II.3 Exemple<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II31_Exemple_simple_de_gestion_de_routes\" >II.3.1 Exemple simple de gestion de routes<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II32_Exemple_de_traitement_dun_formulaire_POST\" >II.3.2 Exemple de traitement d&rsquo;un formulaire POST<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II33_Exemple_de_traitement_dun_formulaire_GET\" >II.3.3 Exemple de traitement d&rsquo;un formulaire GET<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II34_Exemple_de_traitement_dupload_dun_fichier\" >II.3.4 Exemple de traitement d&rsquo;upload d&rsquo;un fichier<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II4_Les_middlewares\" >II.4 Les middlewares<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II41_Presentation_des_middlewares_communs\" >II.4.1 Pr\u00e9sentation des middlewares communs<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II42_Exemple_dutilisation_du_middleware_cookie-session\" >II.4.2 Exemple d&rsquo;utilisation du middleware cookie-session<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#II5_Les_bonnes_pratiques\" >II.5 Les bonnes pratiques<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/blogperso.union31.fr\/?p=1499\/#III_Module_Ejs\" >III Module Ejs<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"I_Introduction_aux_modules_Express_et_Ejs\"><\/span>I Introduction aux modules Express et Ejs<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"I1_Presentation\"><\/span>I.1 Pr\u00e9sentation<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Le module Express permet de g\u00e9rer facilement :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>le routing ;<\/li><li>les sessions ;<\/li><li>l&rsquo;interfa\u00e7age avec un g\u00e9n\u00e9rateur de template (compatible, ici Ejs sera utilis\u00e9).<\/li><\/ul>\n\n\n\n<p>Les documentations sont accessibles aux liens suivants :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>module Express : <a rel=\"noreferrer noopener\" href=\"https:\/\/expressjs.com\/\" target=\"_blank\">https:\/\/expressjs.com\/<\/a> et <a rel=\"noreferrer noopener\" href=\"https:\/\/expressjs.com\/fr\/\" target=\"_blank\">https:\/\/expressjs.com\/fr\/<\/a> traduit en fran\u00e7ais<\/li><li>module Ejs : <a rel=\"noreferrer noopener\" href=\"https:\/\/ejs.co\/\" target=\"_blank\">https:\/\/ejs.co\/<\/a><\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"I2_Installation_dExpress_et_dEjs\"><\/span>I.2 Installation d&rsquo;Express et d&rsquo;Ejs<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install express -save\nnpm install ejs -save<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"I3_Hello_Word\"><\/span>I.3 Hello Word<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Premier exemple permettant de comprendre la structure de base<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const express = require('express')  \n\nconst app = express()\nconst port = 8080\n\napp.get('\/', (req, res) => {\n  res.send('Hello world!')\n})\n\napp.listen(port, () => {\n  console.log(`Ecoute sur http:\/\/localhost:${port} avec Express`)\n})<\/code><\/pre>\n\n\n\n<p>L&rsquo;objet app va g\u00e9rer toutes les connexions entrantes. Ici il \u00e9coute sur le port 8080 et renverra :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>une r\u00e9ponse pour tout acc\u00e8s de type GET sur l&rsquo;url path \u00ab\u00a0\/\u00a0\u00bb<ul><li>ici \u00ab\u00a0Hello world!\u00a0\u00bb<\/li><\/ul><\/li><li>une r\u00e9ponse de non existance d&rsquo;URL path si non d\u00e9finie<\/li><\/ul>\n\n\n\n<p>Exemple de retour pour une URL non g\u00e9r\u00e9e: de type \u00ab\u00a0http:\/\/127.0.0.1\/test\u00a0\u00bb<\/p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<pre class=\"wp-block-code\"><code>Cannot GET \/test<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"I4_Hello_Word_avec_template_Ejs\"><\/span>I.4 Hello Word avec template Ejs<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Les templates sont stock\u00e9s par d\u00e9faut dans un sous r\u00e9pertoire nomm\u00e9 \u00ab\u00a0views\u00a0\u00bb. Le fichier \u00ab\u00a0acceuil.ejs\u00a0\u00bb est cr\u00e9\u00e9 et il contiendra la code suivant :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE html>\n&lt;html>\n\t&lt;head>\n\t\t&lt;title>Hello&lt;\/title>\n\t&lt;\/head>\n\t&lt;body>\n\n\t\t&lt;h1>Acceuil&lt;\/h1>\n\t\t&lt;p> Hello World &lt;\/p>\n\t&lt;\/body>\n&lt;\/html><\/code><\/pre>\n\n\n\n<p>On revient dans le fichier \u00e0 la racine qui sera lanc\u00e9 dans node.js :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const express \t= require('express')\nconst ejs\t= require('ejs'); \n\n\/\/ Instancie l'application express\nconst app = express()\n\/\/ associe le moteur de template Ejs \u00e0 Express\napp.set('view engine', 'ejs');\n\nconst port = 8080\n\napp.get('\/', (req, res) => {\n  \n\t\/\/ r\u00e9cup\u00e8re le template accueil.ejs et envoie le flux http au client\n\tres.render('accueil');\t\n\n})\n\napp.listen(port, () => {\n  console.log(`Ecoute sur http:\/\/localhost:${port} avec Express`)\n})<\/code><\/pre>\n\n\n\n<p>Ici l&rsquo;exemple est plut\u00f4t trivial mais c&rsquo;est le principe g\u00e9n\u00e9ral. On remarque :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>pas besoin de d\u00e9clarer le nom complet du template (accueil.ejs),<\/li><li>pas besoin de fermer la connexion (res.end()). La m\u00e9thode \u00ab\u00a0.render()\u00a0\u00bb s&rsquo;en occupe<\/li><\/ul>\n\n\n\n<p>Deuxi\u00e8me exemple avec un template utilisant un param\u00e8tre qui contiendra \u00ab\u00a0Hello Word\u00a0\u00bb.<\/p>\n\n\n\n<p>Contenu du fichier \u00ab\u00a0accueil.js\u00a0\u00bb :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE html>\n&lt;html>\n\t&lt;head>\n\t\t&lt;title>Hello&lt;\/title>\n\t&lt;\/head>\n\t&lt;body>\n\t\t&lt;h1>Acceuil&lt;\/h1>\n\t\t&lt;p> &lt;%= texte %> &lt;\/p>\n\t&lt;\/body>\n&lt;\/html><\/code><\/pre>\n\n\n\n<p>Ici le code javascript est iclus dans les balise &lt;% &#8230;%&gt;. Et dans ce cas pr\u00e9cis les balises &lt;%= &#8230; %&gt; affiche le contenu de la variable.<\/p>\n\n\n\n<p>On revient dans le fichier \u00e0 la racine qui sera lanc\u00e9 dans node.js :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const express \t= require('express')\nconst ejs\t\t= require('ejs'); \n\n\/\/ Instancie l'application express\nconst app = express()\n\/\/ associe le moteur de template Ejs \u00e0 Express\napp.set('view engine', 'ejs');\n\nconst port = 8080\n\napp.get('\/', (req, res) => {\n  \n  \tlet texte = \"Hello World ! (param\u00e8tre vers le template)\"\n\t\/\/ r\u00e9cup\u00e8re le template accueil.ejs et envoie le flux http au client\n\tres.render('accueil', {texte:texte});\t\n\n})\n\napp.listen(port, () => {\n  console.log(`Ecoute sur http:\/\/localhost:${port} avec Express`)\n})<\/code><\/pre>\n\n\n\n<p>On remarque que :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>la variable texte contient bien \u00ab\u00a0Hello world &#8230;&rsquo;<\/li><li>que cette variable est transmise au template via cette ligne javascript : res.render(&lsquo;accueil&rsquo;, {texte:texte});<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II_Module_Express\"><\/span>II Module Express<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Il est compos\u00e9 de 5 principaux composants :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Express : fonction la plus haut niveau. <ul><li>Retourne un objet de type \u00ab\u00a0Application\u00a0\u00bb pour une simple instiation<\/li><li>Voir en d\u00e9tails en utilisant les m\u00e9thodes sp\u00e9cifiques (peut retourner un objet routeur par ex)<\/li><\/ul><\/li><li>Application : c&rsquo;est l&rsquo;objet principal. Suivant les m\u00e9thodes utilis\u00e9es, et plus particuli\u00e8rement les callback, les objets \u00ab\u00a0Request\u00a0\u00bb et \u00ab\u00a0Response\u00a0\u00bb sont utilis\u00e9s<\/li><li>Request : objet d\u00e9di\u00e9 \u00e0 la demande<\/li><li>Response : objet d\u00e9di\u00e9 \u00e0 la r\u00e9ponse<\/li><li>Router : utilis\u00e9 pour des middlewares personnels dans le cadre du routing.<\/li><\/ul>\n\n\n\n<p>Les objets les plus utilis\u00e9s seront : Application; Request et Responses<\/p>\n<\/div><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II1_Application\"><\/span>II.1 Application<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>C&rsquo;est cet objet qui permettra de faire essentiellement du routing. il faut retenir les m\u00e9thodes suivantes :<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-regular\"><table class=\"has-subtle-light-gray-background-color has-background\"><tbody><tr><td>app.<strong>all()<\/strong><\/td><td>Va traiter tous les types de requ\u00eates HTTP (PUT, GET, DELETE,POST) ou autres.<br>Cette m\u00e9thode est pratique pour mettre en place un logique de mapping global, traiter les authentification des utilisateurs, etc.<\/td><\/tr><tr><td>app.<strong>delete()<\/strong><\/td><td>Va traiter les type de requ\u00eate HTTP DELETE<\/td><\/tr><tr><td>app.<strong>get()<\/strong><\/td><td>Va traiter les type de requ\u00eate HTTP GET<\/td><\/tr><tr><td>app.<strong>listen()<\/strong><\/td><td>Monte un serveur web sur un port particulier.<br>app.listen([port[, host[, backlog]]][, callback])<\/td><\/tr><tr><td>app.<strong>post()<\/strong><\/td><td>Va traiter les type de requ\u00eate HTTP POST<\/td><\/tr><tr><td>app.<strong>put()<\/strong><\/td><td>Va traiter les type de requ\u00eate HTTP PUT<\/td><\/tr><tr><td>app.<strong>render()<\/strong><\/td><td>Pemet d&rsquo;utiliser un moteur de template<\/td><\/tr><tr><td>app.<strong>route()<\/strong><\/td><td>Permet d&rsquo;utiliser une instance d&rsquo;une simple route et d&rsquo;y associe plusieurs middlewares sp\u00e9cifiques asoci\u00e9s \u00e0 la route. <br>ex : <br>app.route(&lsquo;\/events&rsquo;)<br>   .all(function (req, res, next) {<br>   \/\/ runs for all HTTP verbs first<br>   \/\/ think of it as route specific middleware!<br>})<br>.get(function (req, res, next) {<br>   res.json({})<br>})<br>.post(function (req, res, next) {<br>   \/\/ maybe add a new event\u2026<br>})<br>Ceci pour centraliser les r\u00e9ponses \u00e0 faire suivant les requ\u00eates de type GET, POST ou autres pour un m\u00eame chemin. Cela \u00e9vite de faire des erreurs de doublons et clarifie le code<\/td><\/tr><tr><td>app.<strong>use()<\/strong><\/td><td>D\u00e9clare des middleware sp\u00e9cifiques<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II2_Request_et_Response\"><\/span>II.2 Request et Response<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Les objets Request et Response concerne respectivement la requ\u00eate web (resquest) et la r\u00e9ponse \u00e0 faire (response).<\/p>\n\n\n\n<p><span style=\"text-decoration: underline;\">Les m\u00e9thodes\/propri\u00e9t\u00e9s les plus utilis\u00e9es de Request seront :<\/span><\/p>\n\n\n\n<figure class=\"wp-block-table is-style-regular\"><table class=\"has-subtle-light-gray-background-color has-background\"><tbody><tr><td>req.body<\/td><td>obtenir les clefs\/valeurs des donn\u00e9es transmisses dans le body de la requ\u00eate<\/td><\/tr><tr><td>req.hostname<\/td><td>nom du hostname<\/td><\/tr><tr><td>req.ip<\/td><td>adresse ip<\/td><\/tr><tr><td>req.method<\/td><td>M\u00e9thode HTTP utilis\u00e9e (GET, POST, etc.)<\/td><\/tr><tr><td>originalUrl, baseUrl, path<\/td><td>Information sur le niveau des URL.<br>Exemple :<br><em>app.use(&lsquo;\/admin&rsquo;, function (req, res, next) { \/\/ GET &lsquo;http:\/\/www.example.com\/admin\/new&rsquo;<br>   console.dir(req.originalUrl) \/\/ &lsquo;\/admin\/new&rsquo;<br>   console.dir(req.baseUrl) \/\/ &lsquo;\/admin&rsquo; <br>   console.dir(req.path) \/\/ &lsquo;\/new&rsquo;<br>   next()<br>})<\/em><\/td><\/tr><tr><td>params<\/td><td>Permet de r\u00e9cup\u00e9rer des propri\u00e9t\u00e9s au sein d&rsquo;une URL<br>Exemple pour un chemin d\u00e9clar\u00e9 de cette mani\u00e8re \/user\/:name<br><em>\/\/ GET \/user\/tj<br>console.dir(req.params.name)<br>\/\/ =&gt; &lsquo;tj&rsquo;<\/em><\/td><\/tr><tr><td>query<\/td><td>Permet de r\u00e9cup\u00e9rer les variables indiqu\u00e9es dans l&rsquo;url<br>Exemple :<br><em>\/\/ GET \/search?q=tobi+ferret<br>console.dir(req.query.q)   \/\/ =&gt; &lsquo;tobi ferret&rsquo;<br>\/\/ GET \/shoes?order=desc&amp;shoe[color]=blue&amp;shoe[type]=converse<br>console.dir(req.query.order)   \/\/ =&gt; &lsquo;desc&rsquo;<br>console.dir(req.query.shoe.color)  \/\/ =&gt; &lsquo;blue&rsquo;<br>console.dir(req.query.shoe.type)   \/\/ =&gt; &lsquo;converse&rsquo;<br>\/\/ GET \/shoes?color[]=blue&amp;color[]=black&amp;color[]=red<br>console.dir(req.query.color)  \/\/ =&gt; [&lsquo;blue&rsquo;, &lsquo;black&rsquo;, &lsquo;red&rsquo;]<\/em><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><span style=\"text-decoration: underline;\">Les objets\/m\u00e9thodes les plus utilis\u00e9es pour l&rsquo;objet Response seront :<\/span><\/p>\n\n\n\n<figure class=\"wp-block-table is-style-regular\"><table class=\"has-subtle-light-gray-background-color has-background\"><tbody><tr><td>res.send()<\/td><td>Envoi un flux html<\/td><\/tr><tr><td>res.render()<\/td><td>Utilise un template (et\/ou un moteur de template)<\/td><\/tr><tr><td>res.set()<\/td><td>D\u00e9finit les propri\u00e9t\u00e9s du header<\/td><\/tr><tr><td>res.redirect()<\/td><td>Redirection<\/td><\/tr><tr><td>res.json()<\/td><td>Renvoie une r\u00e9ponse sous forme json (header type modifi\u00e9). Prend en param\u00e8tre plein de type de variables (string, tableau, etc)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>La liste n&rsquo;est pas exhaustive mais elle permet de commencer \u00e0 prendre en main simplement ces 2 objets.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II3_Exemple\"><\/span>II.3 Exemple<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Ci dessous quelques exemples d&rsquo;impl\u00e9mentation<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II31_Exemple_simple_de_gestion_de_routes\"><\/span>II.3.1 Exemple simple de gestion de routes<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>const express \t= require('express')\n\nconst app = express()  \t\t\t\/\/ Instancie l'application express\napp.set('view engine', 'ejs'); \t\/\/ associe le moteur de template Ejs \u00e0 Express\nconst port = 8080\n\n\n\/\/ Simple gestion d'acc\u00e8s \u00e0 la racine\napp.get(\"\/\", (req,res)=>{\n\tres.send(\"Bienvenue sur la page d'accueil\")\n})\n\n\/\/ utilisation de route pour l'url \"\/admin\" (gestion du GET et POST au m\u00eame endroit)\napp.route(\"\/admin\").get((req,res,next)=> {\n\tres.send(\"Page admin en GET\")\n}).post ((req,res,next)=> {\n\tres.json (\"{'status' : 'ok'}\")\n})\n\n\/\/ Cas des pages non pr\u00e9sentes : utilisation de son propre middleware\n\/\/   mettre \u00e0 la fin obligatoirement\napp.use(function(req, res, next){\n    res.setHeader('Content-Type', 'text\/plain');\t\/\/ force la sortie en texte\n    res.status(404).send('Page introuvable !');\t\t\/\/ status 404 et texte accompagnant\n});\n\napp.listen(port, () => {\n  console.log(`Ecoute sur le port:${port} avec Express`)\n})\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II32_Exemple_de_traitement_dun_formulaire_POST\"><\/span>II.3.2 Exemple de traitement d&rsquo;un formulaire POST<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>Pour pouvoir r\u00e9cup\u00e9rer simplement les donn\u00e9es de POST, il faudra utiliser un middle-ware sp\u00e9cifique : body-parser.<\/p>\n\n\n\n<p>Ce code r\u00e9cup\u00e8re les informations envoy\u00e9es par un formulaire puis affiche les donn\u00e9es re\u00e7ues sous forme JSON.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n\nconst express \t= require('express')\nconst path \t\t= require('path');\nconst bodyParser = require('body-parser');\n\nconst app = express()  \t\t\t\/\/ Instancie l'application express\napp.set('view engine', 'ejs'); \t\/\/ associe le moteur de template Ejs \u00e0 Express\nconst port = 8080\n\n\/\/ enregistrement du middleware bodyparser\napp.use(bodyParser.json()); \/\/ support json encoded bodies\napp.use(bodyParser.urlencoded({ extended: true })); \/\/ support encoded bodies\n\n\n\/\/ utilisation de route pour l'url \"\/\" (gestion du GET et POST au m\u00eame endroit)\napp.route(\"\/\").get((req,res,next)=> {\n\t\n\t\/\/ renvoie le contenu html du fichier \/views\/fomulaire.html\n\tres.sendFile(path.join(__dirname+'\/views\/formulaire.html'));\n\n}).post ((req,res,next)=> {\n\t\/\/ renvoie sous forme json les param\u00e8tres re\u00e7us\n\tres.json (req.body)    \/\/ body est rempli par le middleware body-parser\n})\n\n\n\/\/ Cas des pages non pr\u00e9sentes : utilisation de son propre middleware\n\/\/   mettre \u00e0 la fin obligatoirement\napp.use(function(req, res, next){\n    res.setHeader('Content-Type', 'text\/plain');\t\/\/ force la sortie en texte\n    res.status(404).send('Page introuvable !');\t\t\/\/ status 404 et texte accompagnant\n});\n\napp.listen(port, () => {\n  console.log(`Ecoute sur le port:${port} avec Express`)\n})\n<\/code><\/pre>\n\n\n\n<p>Il est possible de ne pas passer par le middle-ware \u00ab\u00a0body-parser\u00a0\u00bb. lien montrant comment faire :  <a href=\"https:\/\/www.geeksforgeeks.org\/parsing-form-data-in-express-app-manually-without-body-parser\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.geeksforgeeks.org\/parsing-form-data-in-express-app-manually-without-body-parser\/<\/a><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>exemple particuli\u00e8rement int\u00e9rresant pour comprendre et faire soi-m\u00eame un middleware<\/li><\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II33_Exemple_de_traitement_dun_formulaire_GET\"><\/span>II.3.3 Exemple de traitement d&rsquo;un formulaire GET<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>Dans ce cas, le formulaire envoie les donn\u00e9es vers \/formulaire<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const express \t= require('express')\nconst path \t\t= require('path');\n\nconst app = express()  \t\t\t\/\/ Instancie l'application express\napp.set('view engine', 'ejs'); \t\/\/ associe le moteur de template Ejs \u00e0 Express\nconst port = 8080\n\napp.get(\"\/\",(req,res)=> {\t\n\t\/\/ renvoie le contenu html du fichier \/views\/fomulaire.html\n\tres.sendFile(path.join(__dirname+'\/views\/formulaire_get.html'));\n})\n\napp.get(\"\/formulaire\",(req,res)=> {\n\t\/\/ renvoie les variables du formulaires re\u00e7ues sous forme JSON\n\tres.json(req.query)\n})\n\n\/\/ Cas des pages non pr\u00e9sentes : utilisation de son propre middleware\n\/\/   mettre \u00e0 la fin obligatoirement\napp.use(function(req, res, next){\n    res.setHeader('Content-Type', 'text\/plain');\t\/\/ force la sortie en texte\n    res.status(404).send('Page introuvable !');\t\t\/\/ status 404 et texte accompagnant\n});\n\napp.listen(port, () => {\n  console.log(`Ecoute sur le port:${port} avec Express`)\n})\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II34_Exemple_de_traitement_dupload_dun_fichier\"><\/span>II.3.4 Exemple de traitement d&rsquo;upload d&rsquo;un fichier<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>Pour pouvoir manipuler simplement les upload, il faut utiliser le middle-ware \u00ab\u00a0express-fileupload\u00a0\u00bb.<\/p>\n\n\n\n<p>&#8211; Documentation : <a rel=\"noreferrer noopener\" href=\"https:\/\/www.npmjs.com\/package\/express-fileupload\" target=\"_blank\">https:\/\/www.npmjs.com\/package\/express-fileupload<\/a><\/p>\n\n\n\n<p>Une fois le formulaire lanc\u00e9, cot\u00e9 node.js le fichier se trouveras dans l&rsquo;objet req.files.<\/p>\n\n\n\n<p>Exemple : si la balise est \u00ab\u00a0&lt;input name=\u00a0\u00bbfic\u00a0\u00bb type = \u00ab\u00a0file\u00a0\u00bb&gt;\u00a0\u00bb alors le fichier disponible sera sous node.js \u00ab\u00a0req.file.fic\u00a0\u00bb<\/p>\n\n\n\n<p>Soit le formulaire suivant :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;html>\n  &lt;body>\n    &lt;form ref='uploadForm' \n      id='uploadForm' \n      action='http:\/\/localhost:8000\/upload' \n      method='post' \n      encType=\"multipart\/form-data\">\n        &lt;input type=\"file\" name=\"sampleFile\" \/>\n        &lt;input type='submit' value='Upload!' \/>\n    &lt;\/form>     \n  &lt;\/body>\n&lt;\/html><\/code><\/pre>\n\n\n\n<p>Et le code node.js :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\nconst express \t\t= require('express')\nconst path \t\t= require('path')\nconst fileUpload \t= require('express-fileupload')\n\nconst app = express()  \t\t\t\/\/ Instancie l'application express\napp.set('view engine', 'ejs'); \t\/\/ associe le moteur de template Ejs \u00e0 Express\nconst port = 8080\n\n\/\/ enregistrmement du middle-ware upload : default options\napp.use(fileUpload())\n\napp.get(\"\/\",(req,res)=> {\n\t\/\/ renvoie le contenu html du fichier \/views\/fomulaire.html\n\tres.sendFile(path.join(__dirname+'\/views\/formulaire_upload.html'));\n})\n\napp.post(\"\/upload\",(req,res)=> {\n\n\tif (!req.files || Object.keys(req.files).length === 0) {\n\t    return res.status(400).send('No files were uploaded.');\n\t  }\n\t\/\/ The name of the input field (i.e. \"sampleFile\") is used to retrieve the uploaded file\n\tlet sampleFile = req.files.sampleFile;\n\t\/\/ Use the mv() method to place the file somewhere on your server\n\tsampleFile.mv(path.join(__dirname,\"upload\/\" + req.files.sampleFile.name), function(err) {\n\t\tif (err)\n\t    \treturn res.status(500).send(err);\n\t    res.send(\"Fichier '\" + req.files.sampleFile.name +\"'' upload\u00e9\");\n\t})\n})\n\n\n\/\/ Cas des pages non pr\u00e9sentes : utilisation de son propre middleware\n\/\/   mettre \u00e0 la fin obligatoirement\napp.use(function(req, res, next){\n    res.setHeader('Content-Type', 'text\/plain');\t\/\/ force la sortie en texte\n    res.status(404).send('Page introuvable !');\t\t\/\/ status 404 et texte accompagnant\n});\n\napp.listen(port, () => {\n  console.log(`Ecoute sur le port:${port} avec Express`)\n})\n\n<\/code><\/pre>\n\n\n\n<p>Ne pas h\u00e9siter \u00e0 voir les options sur le site officiel : upload fichiers multiples, limitation taille, cr\u00e9ation r\u00e9pertoire parent, etc&#8230;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II4_Les_middlewares\"><\/span>II.4 Les middlewares<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II41_Presentation_des_middlewares_communs\"><\/span>II.4.1 Pr\u00e9sentation des middlewares communs<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>Comme nous l&rsquo;avons pu le voir, express permet l&rsquo;utilisation de middle-ware. Qu&rsquo;ils soient propres \u00e0 l&rsquo;application (midlle-ware application ou routeur) ou qu&rsquo;ils proviennent de modules tiers (middle-ware tiers).<\/p>\n\n\n\n<p>Ci-dessous une liste des middle-ware tiers \u00e0 prendre en compte :<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-regular\"><table class=\"has-subtle-light-gray-background-color has-background\"><tbody><tr><td>body-parser<\/td><td>Permet de parser automatiquement les variables int\u00e9gr\u00e9 dans le body d&rsquo;une requ\u00eate (ex :formulaires POST)<\/td><td><a href=\"https:\/\/github.com\/expressjs\/body-parser\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/expressjs\/body-parser<\/a><\/td><\/tr><tr><td>compression<\/td><td>Compresse la sortie web<\/td><td><a href=\"https:\/\/github.com\/expressjs\/compression\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/expressjs\/compression<\/a><\/td><\/tr><tr><td><a href=\"https:\/\/github.com\/expressjs\/cookie-session#cookie-session\"><\/a>cookie-session<\/td><td>G\u00e8re les cookies c\u00f4t\u00e9 client et serveur<\/td><td><a href=\"http:\/\/expressjs.com\/en\/resources\/middleware\/cookie-session.html\" target=\"_blank\" rel=\"noreferrer noopener\">http:\/\/expressjs.com\/en\/resources\/middleware\/cookie-session.html<\/a><\/td><\/tr><tr><td><a href=\"https:\/\/github.com\/devoidfury\/express-debug#express-debug\"><\/a>express-debug<\/td><td>Pour debogguer plus facilement (ne pas utiliser en prod)<\/td><td><a href=\"https:\/\/github.com\/devoidfury\/express-debug\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/devoidfury\/express-debug<\/a><\/td><\/tr><tr><td>serv-static<\/td><td>Associe une route \u00e0 un dossier du projet. Cette route pourra directement donner acc\u00e9der \u00e0 tout ou partie du dossier (ex : \/public)<\/td><td><a href=\"https:\/\/github.com\/expressjs\/serve-static\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/expressjs\/serve-static<\/a><\/td><\/tr><tr><td>helmet<\/td><td>S\u00e9curise les applications en d\u00e9finissant certaines propri\u00e9t\u00e9s du header<\/td><td><a href=\"https:\/\/github.com\/helmetjs\/helmet\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/helmetjs\/helmet<\/a><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Ici une liste plus exaustive :<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/expressjs\" target=\"_blank\"> https:\/\/github.com\/expressjs<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II42_Exemple_dutilisation_du_middleware_cookie-session\"><\/span>II.4.2 Exemple d&rsquo;utilisation du middleware cookie-session<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>\nconst express \t\t= require('express')\nconst path \t\t= require('path')\nconst cookieSession     = require('cookie-session')\nconst bodyParser \t= require('body-parser');\n\nconst app = express()  \t\t\t\/\/ Instancie l'application express\napp.set('view engine', 'ejs'); \t\/\/ associe le moteur de template Ejs \u00e0 Express\nconst port = 8080\n\n\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n\/\/ Enregistrement Middleware\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n\n\/\/ enregistrement du middleware bodyparser\napp.use(bodyParser.json()); \/\/ support json encoded bodies\napp.use(bodyParser.urlencoded({ extended: true })); \/\/ support encoded bodies\n\n\/\/ D\u00e9claration du middle-ware session\napp.use(cookieSession({\n  name: 'session_site',\n  keys: &#91;'maphrasesecrete'],\n\n  \/\/ Cookie Options\n  maxAge: 24 * 60 * 60 * 1000 \/\/ 24 hours\n}))\n\n\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n\/\/  Route\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n\n\n\/\/ Accueil\napp.get(\"\/\",(req,res)=> {\n\t\n\t\/\/ sesion existante\n\tif (req.session.auth==undefined) {\n\t\t\/\/ r\u00e9initialise les valeurs\n\t\treq.session.nom \t= \"\"\n\t\treq.session.prenom  = \"\"\n\t\treq.session.auth    = 0\n\t\treq.session.nb_tentative = 0\n\t}\n\n\t\/\/ session authentifi\u00e9 ?\n\tif ( req.session.auth==0) {\n\t\t\/\/ non : renvoi vers formulaire d'authentification\n\t\tres.redirect(\"\/auth\")\n\t} else {\n\t\t\/\/ oui : affichage page accueil personnalis\u00e9e\n\t\tres.render(\"accueil2\",{\"session\" : req.session})\n\t}\t\n\n})\n\n\/\/ formulaire enregistrement\napp.get(\"\/auth\", (req,res)=>{\n\tres.render(\"session\",{\"session\" : req.session})\n})\n\n\/\/ deconnexion : r\u00e9initialisation des valeurs cookies\napp.get(\"\/deconnect\", (req,res)=>{\n\t\n\treq.session.nom \t\t\t= null\n\treq.session.prenom \t\t\t= null\n\treq.session.auth \t\t\t= null\n\treq.session.nb_tentative \t= null\n\tres.redirect(\"\/\")\n})\n\n\n\/\/ v\u00e9rification envoie donn\u00e9es formulaire\napp.post(\"\/auth\", (req,res)=>{\n\n\t\/\/ conditions pour \u00eatre authentifi\u00e9\n\tvar continuer = 1\n\tif (req.body.nom != \"nom\") \t\t\t{continuer = 0}\n\tif (req.body.prenom != \"prenom\") \t{continuer = 0}\n\t\n\t\/\/ renseigne le cookie des valeurs donn\u00e9es\n\treq.session.nom \t= req.body.nom\n\treq.session.prenom \t= req.body.prenom\n\n\t\/\/ authentifi\u00e9 ?\n\tif (continuer == 1) {\n\t\t\/\/ oui\n\t\treq.session.auth = 1\n\t\treq.session.nb_tentative = 0\n\n\t} else {\n\t\t\/\/ non\n\t\treq.session.auth = 0\n\t\treq.session.nb_tentative +=1\n\t}\n\tres.redirect(\"\/\")\n})\n\n\n\/\/ Cas des pages non pr\u00e9sentes : utilisation de son propre middleware\n\/\/   mettre \u00e0 la fin obligatoirement\napp.use(function(req, res, next){\n    res.setHeader('Content-Type', 'text\/plain');\t\/\/ force la sortie en texte\n    res.status(404).send('Page introuvable !');\t\t\/\/ status 404 et texte accompagnant\n});\n\n\n\napp.listen(port, () => {\n  console.log(`Ecoute sur le port:${port} avec Express`)\n})\n\n\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"II5_Les_bonnes_pratiques\"><\/span>II.5 Les bonnes pratiques<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Rien \u00e0 inventer, lire celles du site officiel :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>performance : <a href=\"https:\/\/expressjs.com\/fr\/advanced\/best-practice-performance.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/expressjs.com\/fr\/advanced\/best-practice-performance.html<\/a><\/li><li>s\u00e9curit\u00e9 : <a href=\"https:\/\/expressjs.com\/fr\/advanced\/best-practice-security.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/expressjs.com\/fr\/advanced\/best-practice-security.html<\/a><\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"III_Module_Ejs\"><\/span>III Module Ejs<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>C&rsquo;est un module d\u00e9di\u00e9 au template. Il en existe plusieurs mais celui est assez simple \u00e0 prendre en main.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>site officiel : <a rel=\"noreferrer noopener\" href=\"https:\/\/ejs.co\/\" target=\"_blank\">https:\/\/ejs.co\/<\/a><\/li><li>page npm : <a rel=\"noreferrer noopener\" href=\"https:\/\/www.npmjs.com\/package\/ejs\" target=\"_blank\">https:\/\/www.npmjs.com\/package\/ejs<\/a><\/li><\/ul>\n\n\n\n<p>Ce module s&rsquo;int\u00e8gre \u00e0 expressjs tr\u00e8s simplement. Ca principale force est de pouvoir int\u00e9grer du code javascript au sein du code HTML comme ce qu&rsquo;il peut \u00eatre fait avec PHP.<\/p>\n\n\n\n<p>Il int\u00e8gre \u00e9galement des include, ce qui permet de modulariser tr\u00e8s facilement ses templates.<\/p>\n\n\n\n<p>Pas d&rsquo;exemple ici, le site officiel \u00e9tant particuli\u00e8rement bien d\u00e9taill\u00e9 en terme d&rsquo;exemples.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I Introduction aux modules Express et Ejs I.1 Pr\u00e9sentation Le module Express permet de g\u00e9rer facilement : le routing ; les sessions ; l&rsquo;interfa\u00e7age avec un g\u00e9n\u00e9rateur de template (compatible, ici Ejs sera utilis\u00e9). Les documentations sont accessibles aux liens<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-1499","post","type-post","status-publish","format-standard","hentry","category-_dev"],"_links":{"self":[{"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/posts\/1499","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1499"}],"version-history":[{"count":76,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/posts\/1499\/revisions"}],"predecessor-version":[{"id":1584,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/posts\/1499\/revisions\/1584"}],"wp:attachment":[{"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1499"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1499"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1499"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}