Intro to Express.js
NodeJS #3
Hapi.js
Utilisé par Disney, PayPal, Walmart, Mozilla, Yahoo, Macy's, ...
- Création d'applications et services,
- Basé sur la configuration et les plugins,
- Server side caching,
- Input validation,
Express.js
Utilisé par Myspace, Klout, GeekList, Ghost, Apiary, ...
Auteur initial: TJ Holowaychuk
- Http server library,
- Http routing et middlewares,
- CLI generator,
Koa.js
Auteurs : même team qu'Express
- Basé sur les générateurs ES6,
- Ultra minimaliste,
- Evite le callback spaghetti,
Loopback
Utilisé par GoDaddy, Symantec, BankOfAmerica, ...
- Basé sur Express,
- API framework uniquement,
- Issu de la pateforme StrongLoop (IBM),
- API explorer intégré,
- ACL's ,
- Database agnostique (Mongo, MySQL, Oracle, ...),
Sails
- Rails familiarity,
- Utilise Express pour les requêtes http,
- Frontend agnostique,
- well-defined MVC architecture,
- Waterline : ORM agnostique,
- Blueprint pour générer des API
- Intégre socket.io pour le temps réel
Meteor
- Fullstack JS framework,
- Compatible React ou Angular en frontend,
- Galaxy : Cloud platform,
- DDP : REST for websockets
- Base de donnée partout,
- Communauté++ (+30000 stars)
Mais aussi...
- Derby,
- Kraken,
- Total.js,
- Tower,
- CompoundJS (ex. RailwayJS),
- ...
ExpressJS
npm install express --save
Infrastructure Web minimaliste,
souple et rapide pour Node.js
Réalisation d'applications Web & API
ExpressJS
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
Hello World
ExpressJS
Générateur
sudo npm install express-generator -g
Installation du paquet en global
express monprojet
Ensuite
Routing
Méthodes http
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.post('/', function (req, res) {
res.send('Got a POST request');
});
app.put('/user', function (req, res) {
res.send('Got a PUT request at /user');
});
app.delete('/user', function (req, res) {
res.send('Got a DELETE request at /user');
});
GET
POST
DELETE
PUT
Routing
all
app.all('/secret', function (req, res, next) {
console.log('Accessing the secret section ...');
next(); // pass control to the next handler
});
Dans tous les cas (all)
Routing
Chemins (masques)
app.get('/ab?cd', function(req, res) {
res.send('ab?cd');
});
abcd ou acd
app.get('/ab+cd', function(req, res) {
res.send('ab+cd');
});
abcd ou abbcd ou abbbcd ou ...
app.get('/ab*cd', function(req, res) {
res.send('ab*cd');
});
abcd ou abfoocd ou abbarcd ou ...
Routing
Chaîner les fonctions de rappel
var cb0 = function (req, res, next) {
console.log('CB0');
next();
}
var cb1 = function (req, res, next) {
console.log('CB1');
next();
}
var cb2 = function (req, res) {
res.send('Hello from C!');
}
app.get('/example/c', [cb0, cb1, cb2]);
express.Router
Module
var express = require('express');
var router = express.Router();
router.get('/about', function(req, res) {
res.send('About birds');
});
module.exports = router;
var birds = require('./birds');
...
app.use('/birds', birds);
app.js
birds.js
Request
app.get('/user/:id', function(req, res) {
res.send('user ' + req.params.id);
});
Passer des params (req.params)
Request
// GET /search?q=tobi+ferret
req.query.q
// => "tobi ferret"
Query
req.xhr
// => true
Requête AJAX ?
Response
res.redirect('/foo/bar');
res.redirect('http://example.com');
res.redirect(301, 'http://example.com');
Redirection
// pass a local variable to the view
res.render('user', { name: 'Tobi' }, function(err, html) {
// ...
});
Rendre une vue
Response
res.send({ some: 'json' });
res.send('<p>some html</p>');
res.status(404).send('Sorry, we cannot find that!');
res.status(500).send({ error: 'something blew up' });
Retourner une réponse http
res.json(null);
res.json({ user: 'tobi' });
res.status(500).json({ error: 'message' });
Retourner une réponse JSON
Response
res.download('/r.pdf', 'report.pdf', function(err){
if (err) {
// Handle error, but keep in mind the response
// may be partially-sent
// so check res.headersSent
} else {
// decrement a download credit, etc.
}
});
Télécharger un fichier
Middleware
C'est quoi ?
Les fonctions middleware effectuent les tâches suivantes :
- Exécuter tout type de code.
- Apporter des modifications aux objets de demande et de réponse.
- Terminer le cycle de demande-réponse.
- Appeler le middleware suivant dans la pile.
Middleware
next()
Pour passer au middleware suivant, il faut utiliser la méthode "next" :
next();
Middleware
exemple
var express = require('express');
var app = express();
var myLogger = function (req, res, next) {
console.log('LOGGED');
next();
};
app.use(myLogger);
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.listen(3000);
L'ordre de déclaration des middlewares est important !
Middleware
Niveau app
var app = express();
app.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
Possibilité de le brancher sur un point de montage
Middleware
Niveau router
var express = require('express');
var router = express.Router();
router.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
Middleware
Tiers
var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');
// load the cookie-parsing middleware
app.use(cookieParser());
Parse Cookie header and populate req.cookies with an object keyed by the cookie names
Middleware
Erreurs
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
4 arguments au lieu de 3 !
Middleware
Fichiers statiques
app.use(express.static(path.join(__dirname, 'public')));
var options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now());
}
}
app.use(express.static('public', options));
Configurable
Vues
Moteurs de rendu
npm install --save-dev jade
En CLI :
Dans app.js
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
Dans les routes
app.get('/', function (req, res) {
res.render('index', { title: 'Hey' });
});
Vues
Moteurs de rendu
Autres moteurs de rendu possibles
EJS,
Handlebars,
Hogan
JADE par défaut
Vues
Jade
Class Literal
a.button
.content
ID Literal
a#button
#button
<a class="button"></a>
<div class="content"></div>
<a id="button"></a>
<div id="content"></div>
a(class={active: currentUrl === '/'} href='/') Home
Class attributes
- var classes = ['foo', 'bar', 'baz']
a(class=classes)
Vues
Jade
Attributes
a.button(href='google.com') Google
<a href="google.com" class="button">Google</a>
input(
type='checkbox'
name='agreement'
checked
)
<input type="checkbox" name="agreement" checked="checked"/>
Vues
Jade
Unbuffered code
- list = ["Uno", "Dos", "Tres"]
each item in list
li= item
Buffered code
p= 'This code is' + ' <escaped>!'
p!= 'This code is' + ' <strong>not</strong> escaped!'
<p>This code is <strong>not</strong> escaped!</p>
<p>This code is <escaped>!</p>
Vues
Jade
- var friends = 10
case friends
when 0
p you have no friends
when 1
p you have a friend
default
p you have #{friends} friends
Case
Vues
Jade
- var user = { description: 'foo bar baz' }
- var authorised = false
#user
if user.description
h2 Description
p.description= user.description
else if authorised
h2 Description
p.description.
User has no description,
why not add one...
else
h1 Description
p.description User has no description
Conditions
Vues
Jade
//- layout.jade
doctype html
html
head
block title
title Default title
body
block content
Extends
//- index.jade
extends ./layout.jade
block title
title Article Title
block content
h1 My Article
+
Vues
Jade
//- index.jade
doctype html
html
include ./head.jade
body
h1 My Site
p Welcome
include ./foot.jade
Includes
//- foot.jade
#footer
p Copyright (c) foobar
+
En cas de doute : http://html2jade.org
Vues
Jade
exercice
Vues
Jade
- var items = { '/': 'Home', '/users': 'Users', '/settings': 'Settings' };
// 1) itérer sur l'object pour afficher le markup d'un menu
// * Les clés correspondent au href des liens,
// * Les valeurs correspondent aux textes des liens
// --> Le menu doit être une liste <ul> de liens <li>
// 2) Attribuer une classe "odd" aux liens dont l'index est pair
// Attribuer une classe "even" aux liens dont l'index est impair
exercice
Générer une application express à l'aide du générateur.
En utilisant la session, gérer une liste d'utilisateurs (affichage de la liste, ajout dans la liste et suppression)
- Utiliser la route "/users" en GET pour afficher le form et la liste.
- Créer une route "/users" en POST pour soumettre le form.
- Créer une route "/users/delete/1" en GET pour supprimer un user de la session (1 étant l'index dynamique)
[NODEJS] NodeJS frameworks (cours 3)
By Julien Herpin
[NODEJS] NodeJS frameworks (cours 3)
- 1,193