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

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 &lt;escaped&gt;!</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