Frameworks coté Serveur

On s’intéresse à la réalisation d’applications Web classiques (côté serveur) où les données dynamiques sont stockées dans des bases de données et les pages Web générées côté serveur à partir de templates.

Web Application Frameworks

Les applications Web (côté client ainsi que côté serveur) ont besoin de serveurs Web et d’autres frameworks liés au réseau.

Les frameworks d’applications Web gèrent toutes les parties techniques de la communication entre le client et le serveur, notamment :

Express (expressjs.com). Un framework Web minimaliste pour Node.js.

Les frameworks d’applications Web sont des outils essentiels pour simplifier le développement d’applications Web. Ils gèrent divers aspects techniques tels que la gestion des requêtes HTTP, la sécurité, le routage, et plus encore. Express est l’un de ces frameworks, spécialement conçu pour Node.js

const express = require('express');
const port = 1337;

const app = express();

app.get('*', function(req, res){
  res.send('<h1>Hello World</h1>');
});
let server = app.listen(port, ()=>console.log(`http://localhost:${port}/`));

Installez-le avec npm : npm install express

Utilisez express-generator pour créer un projet de base :

npm i -g express-generator
npx express-generator --view=pug nomProjet

Routage avec Express

Dans une application Web, le routage fait référence à la manière dont les URL (Uniform Resource Locators) sont associées à des actions spécifiques. Express facilite la création de routes en associant des URL à des fonctions de traitement pour gérer les différentes actions HTTP telles que la récupération (GET), la création (POST) et la suppression (DELETE) de ressources. Les paramètres de route, comme :id?, permettent de capturer des valeurs variables dans l’URL.

app.get('/advert/:id?', function(req, res) {
    res.send('You asked for advert' + req.params.id);
})
.get('/search', function(req, res) { //search?q=something+fun
    console.log('the search query is: ' + req.query.q); // req.param('q')
})
.post('/advert', function(req, res){ // avec le middleware bodyParser() 
    req.body.advertTittle
})
.delete('/advert/:id?', function(req, res) {
    // supprimer l'entrée req.param('id') de la base de données
});

Templates avec Express

Dans le fichier de configuration principal d’Express (app.js`):

app.set('view engine', 'pug');
var users = [{id:'1', name:'Tom'},
            {id:'2', name:'Max'}];
app.get('/user/:id?', function(req, res){
  res.render('hello_user', users.filter( user => user.id === req.params.id )[0]);
});

Dans un fichier template (views/hello_user.pug) en utilisant la bibliothèque Pug (https://pugjs.org):

.user
  h2 Hello #{name}!

Result:

<div class="user">
    <h2>Hello Max!</h2>
</div>

Middleware Express

Example classical Express middleware configuration

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// Configuration du moteur de vues
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// Gestion des erreurs 404 et renvoi vers le gestionnaire d'erreurs
app.use(function(req, res, next) {
  next(createError(404));
});

// Gestionnaire d'erreurs
app.use(function(err, req, res, next) {
  // Configuration des variables locales, fourniture de l'erreur uniquement en mode développement
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // Renvoi de la page d'erreur avec le code d'erreur approprié
  res.status(err.status || 500);
  res.render('error');
});

Bases de données

ien sûr, les systèmes de gestion de base de données relationnelles classiques sont adaptés aux applications Web, mais les systèmes de base de données NoSQL peuvent être utiles dans les cas suivants :

Il existe (au moins) quatre types de systèmes de base de données NoSQL :

Projets célèbres:

MongoDB(www.mongodb.org): une base de données NoSQL de stockage orientée objet

Les documents sont stockés dans un format JSON-like (BSON : représentation binaire de JSON).

{
  "_id": ObjectId("507f1f77bcf86cd799439011"),
  "title": "My new house in the city",
  "text": "<h2>Great new house</h2>",
  "plot_id": "-628141",
  "available_date": ISODate("2018-11-17T08:30:00.000Z"),
  "high_priority": false,
  "surface_area": 230
}

Mongoose (mongoosejs.com) un ODM (Object Document Mapper) pour MongoDB et Node.

Créer de nouveaux objets modèle.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const animalSchema = new Schema(
  {
    name: String,
    type: String,
    age: { type: Number, default: 0 },
    birthday: { type: Date, default: Date.now },
  }
);
const Animal = mongoose.model('Animal', animalSchema);
const dog = new Animal({ type: 'dog' });

Connexion à une base de données Mongo et requête d’objets.

(async () => {
  await mongoose
    .connect("mongodb://localhost:27017/test", {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    })
    .catch((err) => console.log("CONNECT", err));

  const Animal = mongoose.models.Animal;

  const createDogs = [
    new Animal({ name: "Paf", type: "dog", age: 4 }),
    new Animal({ name: "Tobi", type: "dog", age: 5 }),
    new Animal({ name: "BebePaf", type: "dog" }),
  ].map(async (animal) => {
    await animal.save().catch((err) => console.log("save error", err));
  });
  await Promise.all(createDogs);

  let dogs = await Animal.find({ type: "dog" })
    .where("age")
    .gt(2)
    .lt(8) // contrainte
    .sort({ age: -1 }) // tri
    .select({ name: 1, age: 1 }); // selection de colonnes
  //.lean() // conversion en objets JS simples

  const saveDogs = dogs.map(async (dog) => {
    dog.age++;
    const saveDog = await dog.save().catch((err) => console.log("SAVE error"));
    return saveDog;
  });

  dogs = await Promise.all(saveDogs);

  console.log(dogs);

  mongoose.disconnect().catch((err) => console.log("DISCONNECT", err));
})(); // async IIFE

Utilisation de MongoDB avec Express.

app.post('/api/projects', auth.ensureAuthenticated, createProject);

function createProject(req, res) {
  var project = new Project(req.body);
  project.creator = req.user;
  project.save(function(err) {
    if (err) {
      res.status(500).json(err);
    } else {
      if (!req.user.hasProjects) {
        User.update({
          _id: req.user._id
        }, {
          hasProjects: true
        }, function(err) {
          if (err) {
            res.status(500).json(err);
          }
        });
      }
      res.json(project);
    }
  });
};

Authentification

Plusieurs solutions sont possibles, mais Passport) semble la plus viable. Ce billet de blog donne un bon exemple.