-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path09-express.html
275 lines (247 loc) · 12.9 KB
/
09-express.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
<section id="express">
<section>
<h2>Express</h2>
</section>
<section>
<h2>Introduction</h2>
<div class="container">
<div class="col">
<p>Express est un <strong>framework HTTP</strong> permettant de faciliter la création d'un serveur web.</p>
<p>Il s'agit d'un framework "lite" ne comprenant que les <strong>fonctionnalités basiques</strong> d'un framework web (routing, fichiers statiques, middlewares, ...).</p>
</div>
<div class="col">
<img src="assets/images/express.png" alt="Express">
</div>
</div>
<footer>
<a href="https://expressjs.com" class="info" target="_blank">ExpressJS</a>
</footer>
</section>
<section>
<h3>Mise en place du projet</h3>
<p>Express dispose d'un <strong>générateur</strong> (<a href="https://expressjs.com/en/starter/generator.html">express-generator</a>) permettant de générer une structure de projet.</p>
<p>Cependant, nous n'allons pas l'utiliser afin de construire <strong>étape par étape</strong> notre application web.</p>
<p>Pour ce cours, nous allons utiliser un <strong>projet fil rouge</strong> : SocialQuiz</p>
<p>L'objectif sera de créer une application web permettant aux internautes de créer des quiz catégorisés de façon collaborative.</p>
</section>
<section>
<h3>Installation</h3>
<p>Créez un dossier socialquiz et positionnez-vous dans ce dossier depuis votre terminal.</p>
<p>Créer ensuite un nouveau projet NPM :</p>
<pre><code class="language-bash">npm init</code></pre>
<p>Créez ensuite un fichier app.js qui sera le point d'entrée de notre application.</p>
<p>Installez ensuite Express avec la commande suivante :</p>
<pre><code class="language-bash">npm install --save express</code></pre>
<p>Installez ensuite Nodemon pour simplifier le développement de notre application.</p>
</section>
<section>
<h3>Utilisation de Express</h3>
<p>Nous allons maintenant importer le module <strong>express</strong> et l'utiliser pour créer notre serveur web :</p>
<pre class="line-numbers"><code class="language-js">const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello world!');
});
app.listen(8000);</code></pre>
</section>
<section>
<h3>Moteur de template</h3>
<p>Par défaut, <strong>aucun moteur de template</strong> n'est installé. Cependant, il est possible d'ajouter un moteur de template à Express.</p>
<p>Express supporte plusieurs moteurs de template (Pug, Mustache, EJS...) mais celui recommandé dans la documentation est <strong>Pug</strong> (anciennement Jade).</p>
<p>Nous allons donc ajouter le moteur de template Pug dans nos dépendances :</p>
<pre><code class="language-bash">npm install --save pug</code></pre>
<footer>
<a href="https://expressjs.com/en/guide/using-template-engines.html" class="info" target="_blank">Moteur de template</a>
</footer>
</section>
<section>
<h3>Pug</h3>
<p>Nous allons maintenant activer le moteur de template dans Express :</p>
<pre><code class="language-js">app.set('view engine', 'pug');</code></pre>
<p>Nous allons maintenant utiliser la fonction <code class="language-js">render()</code> pour retourner un fichier .pug :</p>
<pre><code class="language-js">res.render('index', { username: 'johndoe' });</code></pre>
<p>Créez ensuite un fichier index.pug dans un nouveau dossier nommé "views".</p>
<footer>
<a href="#" class="warning" style="font-size: 0.7em">Il est possible de modifier le dossier contenant les vues avec la fonction app.set('views', ...)</a>
</footer>
</section>
<section>
<h3>Pug</h3>
<p>Le moteur de template Pug utilise l'indentation pour organiser le code HTML (pas de balises).</p>
<p>Ajoutez le code suivant dans le fichier index.pug :</p>
<pre class="line-numbers"><code class="language-pug">// index.pug
doctype html
html
head
title SocialQuiz
body
h1= username
</code></pre>
<footer>
<a href="https://pugjs.org" class="info" target="_blank">Documentation de Pug</a>
</footer>
</section>
<section>
<h3>Pug - héritage</h3>
<p>Pug permet d'effectuer de l'héritage dans les templates. Cela permet d'éviter de répéter le même code sur l'ensemble des pages :</p>
<pre class="line-numbers" data-line="7"><code class="language-pug">// layout.pug
doctype html
html
head
title SocialQuiz
body
block content
</code></pre>
<pre class="line-numbers" data-line="2,4"><code class="language-pug">// index.pug
extends layout.pug
block content
h1= username
</code></pre>
</section>
<section>
<h3>Pug - variables</h3>
<p>Il est possible d'afficher des variables dans un template pug de plusieurs façon. Nous avons déjà affiché le nom de l'utilisateur dans la variable h1 : <code class="language-pug">h1= username</code>.</p>
<p>Nous allons maintenant afficher le titre de la page dans la balise <strong>title</strong> :</p>
<pre class="line-numbers" data-line="5"><code class="language-pug">// layout.pug
doctype html
html
head
title SocialQuiz - #{title}
body
block content</code></pre>
<p>Ajoutez ensuite un nouveau paramètre dans la fonction <code class="language-js">render()</code> dans le fichier app.js</p>
</section>
<section>
<h3>Gestion des assets</h3>
<p>Nous allons à présent ajouter une feuille CSS à notre projet.</p>
<p>Créez un nouveau dossier <strong>public/css</strong> puis ajouter un nouveau fichier <strong>style.css</strong> à l'intérieur avec le code suivant :</p>
<pre class="line-numbers" style="height: 100px; overflow: auto;"><code class="language-css">/* style.css */
:root {
--main-bg-color: #ccc;
}
body {
background-color: var(--main-bg-color);
}</code></pre>
<p>Ajoutez ensuite une balise link dans le header du site :</p>
<pre class="line-numbers" data-line="5"><code class="language-pug">// layout.pug
doctype html
html
head
title SocialQuiz - #{title}
link(rel='stylesheet', href='/css/style.css')
body
block content</code></pre>
</section>
<section>
<h3>Gestion des assets</h3>
<p>Malheureusement, le chargement du fichier CSS ne fonctionne pas. Etant donné qu'il s'agit d'un fichier statique, il faut indiquer à Express de ne pas traiter l'appel de ce fichier comme une route de notre application :</p>
<pre><code class="language-js">app.use(express.static('public'));</code></pre>
<p>Nous pouvons également définir une route général pour l'ensemble de nos assets afin d'éviter les conflits avec nos autres routes :</p>
<pre><code class="language-js">app.use('/public', express.static('public'));</code></pre>
<pre><code class="language-pug">link(rel='stylesheet', href='/public/css/style.css')</code></pre>
</section>
<section>
<h3>Les middlewares</h3>
<div class="container">
<div class="col" style="flex: 2;">
<p>Les middlewares sont des fonctions ayant accès aux objets <code class="language-js">req</code> et <code class="language-js">res</code> ainsi qu'à la prochaine fonction qui devra être exécutée : <code class="language-js">next()</code>.</p>
<p>Ils peuvent :</p>
<ul>
<li>Exécuter du code</li>
<li>Modifier les objets <code class="language-js">req</code> et <code class="language-js">res</code></li>
<li>Terminer un requête</li>
<li>Appeler le middleware suivant</li>
</ul>
</div>
<div class="col">
<img src="assets/images/middlewares.png" alt="Middlewares">
</div>
</div>
</section>
<section>
<h3>Les middlewares</h3>
<p>Les middlewares peuvent être appelés via la fonction <code class="language-js">app.use()</code> ou bien pour un type de requête spécifique avec <code class="language-js">app.METHOD()</code> (où METHOD peut être "get", "post", "put"...).</p>
<div class="instructions">
<ol>
<li>Créez un middleware pour logger dans la console l'adresse IP de l'utilisateur sur chaque requête.</li>
</ol>
</div>
</section>
<section>
<h3>Gestion des formulaires</h3>
<p>Afin de pouvoir récupérer les informations transmises via nos formulaires, nous allons utiliser un middleware basé sur le package <a href="https://www.npmjs.com/package/body-parser" target="_blank">body-parser</a> :</p>
<pre><code class="language-js">const bodyParser = require('body-parser');
app.use(bodyParser.json()); // Parser application/json
app.use(bodyParser.urlencoded({ extended: true })); // Parser application/x-www-form-urlencoded</code></pre>
<p>Il sera ensuite possible de récupérer les informations des formulaire via la variable <code class="language-js">req.body</code>.</p>
</section>
<section>
<h3>Gestion des formulaires</h3>
<div class="instructions">
<ol>
<li>Créez un formulaire contenant un titre et un contenu</li>
<li>Créez une nouvelle route pour gérer l'envoi du formulaire</li>
<li>Affichez dans la console les données envoyées par l'utilisateur</li>
<li>Redirigez l'utilisateur vers la page d'accueil</li>
</ol>
</div>
</section>
<section>
<h3>Gestion des formulaires</h3>
<p>Nous allons maintenant mettre à jour notre formulaire pour permettre à l'internaute <strong>d'uploader</strong> une image.</p>
<p>Pour cela, nous allons utiliser un middleware basé sur le package <a href="https://www.npmjs.com/package/multer" target="_blank">multer</a> : </p>
<pre><code class="language-js">const multer = require('multer');
const storage = multer.diskStorage({
destination: 'public/uploads/',
filename: (req, file, cb) => {
console.log(file)
const fileinfo = path.parse(file.originalname);
cb(null, fileinfo.name + '-' + Date.now() + fileinfo.ext);
}
});
const upload = multer({ storage: storage }); // Parser multipart/form-data
app.post('/question', upload.single('image'), (req, res) => {</code></pre>
<footer>
<a href="#" class="warning">N'oubliez pas d'ajouter l'attribut enctype dans le formulaire</a>
</footer>
</section>
<section>
<h3>La variable locals</h3>
<p>Il existe deux variables <code class="language-js">app.locals</code> et <code class="language-js">res.locals</code> permettant respectivement de gérer des variables au niveau de l'application ou bien spécifiquement pour chaque réponses.</p>
<p>Ces variables sont accessibles dans les vues Pug.</p>
<div class="instructions">
<ol>
<li>Définissez un objet comme variable d'application</li>
<li>Ajoutez une propriété contenant le nom du site</li>
<li>Ajoutez une propriété contenant la version du site</li>
<li>Récupérez ces données en utilisant la variable <code class="language-js">process.env</code></li>
</ol>
</div>
</section>
<section>
<h3>Les sessions</h3>
<p>Pour gérer les sessions de notre application, nous allons utiliser le package <a href="https://www.npmjs.com/package/express-session" target="_blank">express-session</a></p>
<p>Utiliser ensuite ce middleware :</p>
<pre><code class="language-js">const session = require('express-session');
app.use(session({
secret: 'changethis',
resave: false,
saveUninitialized: true
}));</code></pre>
<p>Vous pouvez ensuite accéder aux variables de session en utilisant <code class="language-js">req.session</code></p>
<footer>
<a href="#" class="warning" style="font-size: 0.8em;">En production, il est préférable de stocker les sessions en base de données</a>
</footer>
</section>
<section>
<h3>Les sessions</h3>
<div class="instructions">
<ol>
<li>Créez un nouveau fichier middlewares/errors.js</li>
<li>Dans ce middleware, ajoutez une fonction <strong>errors</strong> sur l'objet <code class="language-js">req</code></li>
<li>Cette fonction <strong>errors</strong> devra ajouter en session les erreurs à afficher</li>
<li>Affichez ensuite ces erreurs dans le fichier layout.pug</li>
</ol>
</div>
</section>
</section>